1

I have two child view controllers in my parent view controller, I want to call them upon a value change in the segmented control, and want to set the value of the parent imageView through child view controllers.

protocol UserEdittedPhoto {
    func UserIsDone(image:UIImage)
}

class ControllerFinal:UIViewController, UserEdittedPhoto{

    func UserIsDone(imageEditted: UIImage){
        self.usedImage=imageEditted
        self.imageView.image=self.usedImage
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func segmentAction(sender:UISegmentedControl){

        if (segmentedControl.selectedSegmentIndex==0){

            performSegueWithIdentifier("EditIAm", sender: nil)
        }

        else if (segmentedControl.selectedSegmentIndex==1){

            performSegueWithIdentifier("EditIAm", sender: nil)
        }
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        if segue.identifier == "EditIAm"{

            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let controller = storyboard.instantiateViewControllerWithIdentifier("ControllerEdit")
            self.presentViewController(controller, animated: true, completion: nil)

            let nextView = segue.destinationViewController as! ControllerEdit
            nextView.originalImage=self.imageView.image!
            nextView.delegate=self
        }

        else if segue.identifier == "FilterIAm"{

            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let controller = storyboard.instantiateViewControllerWithIdentifier("ControllerFilters")
            self.presentViewController(controller, animated: true, completion: nil)

            let nextView = segue.destinationViewController as! ControllerFilters
            nextView.toBeFilter=self.imageView.image!
        }
    }

    class ControllerEdit:UIViewController{
        var delegate: UserEdittedPhoto? = nil
        if (delegate != nil){
        self.originalImage = UIImage(CIImage: CIImage(image: self.originalImage)!.exposureAdjustFilter(sliderValue.value)!)
        self.delegate!.UserIsDone(self.originalImage)
        print("I am Called!")
        }
    }

    class ControllerFilters:UIViewController{
        override func viewDidLoad() {
            print("SAHASHhqdwiuhiuhsaiuhsaiudhiuash")
            controllerFinal?.imageView.image=toBeFilter
            print("SAHASHhqdwiuhiuhsaiuhsaiudhiuash")
            super.viewDidLoad()
        }
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291

2 Answers2

2

UPDATE

To reflect our discussion in the comments below, I don't think you really need Containers and View Controllers to manage your custom controls (Edit / Filters). It's overkill.

Instead, I think you should be creating custom Views, and then adding them to your main Storyboard.

Then you could simply hide/show your custom Views when users tap on the Segmented Control as well as passing values to them, for example:

CustomEditView.valueY = newValueY
CustomFiltersView.valueX = newValueX

Regarding:

I need to call it forcefully through segmentedControl action, so that my values in the childView be updated

Then you need to map the target View Controllers to local variables and use them to update the target View Controller variables when users presses the segments.

I've update the code and "demo" in my answer to reflect that.
(Notice that I'm just putting random Strings in the labels to make a point.)

Now to the complete answer...


In the setup you described in your other question, which is based on containers, the View Controllers are already there, in the Storyboard. You absolutely don't need to present them again (you can remove performSegueWithIdentifier calls).

If I understood correctly, you just want to show different "controllers" to the user based on what they choose via a Segmented Control.

There are some ways for doing that, but the easiest one would be to hide and to show the containers of the ControllerEdit / ControllerFilters View Controllers -- by changing the containers isHidden variable state.

Like this:

demo

Storyboard setup:

storyboard

Code (based on my other answer):

import UIKit

protocol UpdateImageProtocol {
    func userIsDone(image: UIImage)
}

class ViewController: UIViewController, UpdateImageProtocol {

    @IBOutlet weak var imageView: UIImageView!

    @IBOutlet weak var changeImageContainer: UIView!
    var controllerEdit: ControllerEdit?

    @IBOutlet weak var applyFilterContainer: UIView!
    var controllerFilters: ControllerFilters?

    var image = UIImage(named: "hello")

    override func viewDidLoad() {
        super.viewDidLoad()
        userIsDone(image: image!)
    }

    func userIsDone(image: UIImage) {
        imageView.image = image
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "controllerEdit" {
            let nextView = segue.destination as! ControllerEdit
            nextView.delegate = self
            controllerEdit = nextView

        } else if segue.identifier == "controllerFilters" {
            let nextView = segue.destination as! ControllerFilters
            controllerFilters = nextView
        }
    }

    @IBAction func segmentAction(_ sender: UISegmentedControl) {
        if sender.selectedSegmentIndex == 0 {
            changeImageContainer.isHidden = false
            applyFilterContainer.isHidden = true

            controllerEdit?.customLabel.text = String(arc4random_uniform(999))

        } else {
            changeImageContainer.isHidden = true
            applyFilterContainer.isHidden = false

            controllerFilters?.customLabel.text = String(arc4random_uniform(999))
        }
    }
}

class ControllerEdit: UIViewController {

    @IBOutlet weak var customLabel: UILabel!

    var image = UIImage(named: "newHello")
    var delegate: UpdateImageProtocol?

    @IBAction func changeImage(sender: UIButton) {
        delegate?.userIsDone(image: image!)
    }
}

class ControllerFilters: UIViewController {

    @IBOutlet weak var customLabel: UILabel!

    // TODO
}
Graham
  • 7,431
  • 18
  • 59
  • 84
backslash-f
  • 7,923
  • 7
  • 52
  • 80
  • I have basic edits for pictures in view1 and some filters in view2, is it a good approach to just show and hide the child view? @backslash-f – Zuhaib Rasheed Mar 25 '17 at 20:18
  • I need to pass updated values from segue to childviewController every time i press the segmented control, but it is only called once at the start and then it shows and hide itself. @backslah-f – Zuhaib Rasheed Mar 25 '17 at 21:36
  • That would work, but personally I don't think it's a very good approach from an architecture standpoint... It doesn't seem you really need View Controllers to handle your custom controllers. It's overkill. It would be better to create custom Views and simple show/hide these custom Views. I wrote a tutorial on that: http://stackoverflow.com/documentation/ios/1362/custom-uiviews-from-xib-files#t=201703252136398973902, take a look. I'll update my answer with this info. – backslash-f Mar 25 '17 at 21:38
  • Regarding "I need to pass updated values from segue to childviewController every time i press the segmented control", those would be vars in your custom Views. Then each time the user press the Segmented Control, you would, for example: "editView.customValue = value" / "filterView.customValue = value". – backslash-f Mar 25 '17 at 21:43
  • I dont think i understood this, i mean i have to pass imageView value every time user clicks the segmentedControl and am doing this through segue but it is called only once not every time i click upon the segmentedControl. @backslash-f – Zuhaib Rasheed Mar 25 '17 at 21:47
  • Which part you didn't understand? – backslash-f Mar 25 '17 at 21:49
  • Where to update the value of childView variable? In the segue or in the segmented action controller? If in the segmentedController action, then how to? @backslash-f – Zuhaib Rasheed Mar 25 '17 at 21:54
  • If you are going to stick with your current setup (Containers / View Controllers), then update the value of childView variables in the prepareForSegue function. If you are going to user custom Views, then update the custom View variables in the segmented control. – backslash-f Mar 25 '17 at 21:57
  • I am sticking with my setup for now (Container/ViewController), Sir, this is what am doing updating the values of childVariables through segue function, but the segue is called only once. I need to call it forcefully through segmentedControl action, so that my values in the childView be updated. i need a solution for this. Thankyou so much in advance you are already helping me out a lot. @backslash-f – Zuhaib Rasheed Mar 25 '17 at 22:02
  • Not in github yet, will upload tomorrow if you say. – Zuhaib Rasheed Mar 25 '17 at 22:03
  • I see. In this case you need to map the target View Controllers under prepareForSegue to local variables, and update them when users presses a segment. I've updated my answer showing how, take a look. – backslash-f Mar 25 '17 at 22:34
  • Hey! It solved the problem, thankyou so much. @backslash-f – Zuhaib Rasheed Mar 26 '17 at 15:26
1

Put a breakpoint in this function:

@IBAction func segmentAction(sender:UISegmentedControl){

    if (segmentedControl.selectedSegmentIndex==0){

        performSegueWithIdentifier("EditIAm", sender: nil)
    }

    else if (segmentedControl.selectedSegmentIndex==1){

        performSegueWithIdentifier("EditIAm", sender: nil)
    }
}

If it's not getting called, then you probably didn't connect it to an action in IB (is the circle to the left of the the @IBAction filled in?)

If it is getting called, then make sure the segue names are right -- also, fix the one in the else if, because it looks like you want "FilterIAm" there.

Then, put a breakpoint in prepareForSegue:... -- is that getting called? If not, recheck the names are the same as in IB.

EDIT: based on comment

Your prepareForSegue is not supposed to create the ViewController. The destination view controller is created as a consequence of performing the segue and passed to this function.

if segue.identifier == "EditIAm"{
    let nextView = segue.destinationViewController as! ControllerEdit
    nextView.originalImage=self.imageView.image!
    nextView.delegate=self
}

You don't need to present anything -- the destinationViewController is going to be presented. You can set any of its variables (as you have) - that is what is meant by preparing for the segue.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
  • can you please check prepareforsegue function, i think the error is in that function, i want to present childviewController and pass value to it. Is it correct? @LouFranco – Zuhaib Rasheed Mar 25 '17 at 16:15