4

I currently have a base view controller say AVC which present another view controller say BVC over current context like this:

let bvc: BVC = sb.instantiateViewControllerWithIdentifier("BVC") as! BVC
bvc.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.presentViewController(bvc, animated: true, completion: nil)

Then I am setting a value in BVC and on dismiss, am using the same value to perform a function in the viewWillAppear of AVC. However, I noticed that when presenting OverCurrentContext, on dismiss, the viewWillAppear does not called.

How do I go about fixing this? I need a semi-transparent presented view and hence would need to use OverCurrentContext.

Thanks!

Shivam Bhalla
  • 1,879
  • 5
  • 35
  • 63

2 Answers2

7

bhalla,

Two ways,

Way 1

You can make use of delegates and protocol for this :)

Declare a protocol in BVC and confirm it in AVC. And when you are done in BVC call the method of protocol and let the AVC dismiss BVC and by doing that you can pass the data from BVC to AVC as well.

Example :

Declare a protocol like the one below in BVC

protocol letsCallParent{
    func amDoneHere(dataIwantToPass : String)
}

Declare a property to hold the reference of view controller confirming to this protocol in BVC

var myParent : letsCallParent?

And when you are done with BVC and you have to dismiss youself call the method in delegate and pass the data you want to pass :) Now it would be good coding practice to expect the parent (AVC) to dismiss BVC rather then call dismissViewController on self :)

if let parent = myParent {
    parent.amDoneHere("Hi am Done here")
}

In AVC confirm to the protocol using

class AVC: UIViewController,letsCallParent{

and after instantiating BVC before presenting it assign the self as myParent of BVC :)

let bvc: BVC = sb.instantiateViewControllerWithIdentifier("BVC") as! BVC
bvc.myParent = self

and finally implement the protocol method :)

func amDoneHere(dataIwantToPass: String) {
   print("\(dataIwantToPass)")
   //if you want to dismiss BVC call 
   //if you have pushed bvc
   //self.navigationController?.popToViewController(self, animated: true)
   //if you have presented
   //self.dismissViewControllerAnimated(true, completion: nil)
}

WAY 2

Make use of unwind segue :) making use of unwind segue will eliminate the need to write delegate and protocols and all :) also provides the parent view controller an opportunity to access the child view controller as well :) Once you have an access to child VC which is BVC you can read the data from it :)

Example :

Declare an unwind segue :) If you want BVC to call a metod of AVC when it gets dimissed, declare a unwind segue method in AVC :)

@IBAction func cancelChildVC(segue:UIStoryboardSegue) {
        let childVC : SecondViewController = segue.sourceViewController as! SecondViewController
        print(childVC.name)
        self.dismissViewControllerAnimated(true, completion: nil)
}

The signature of the method is fixed :) It has to be a @IBAction and it has to accept segue as paramter :)

Only after declaring this method :) go to your story board and select the BVC and hold control and drag from the button or any other view you have in BVC to dismiss it, to Exit option in BVC :)

Have look at gif provided below for clear understanding :)

enter image description here

If you do it correctly you will see the method that you have declared in AVC coming up as pop up option :) select it :) Thats it :) Whenever you tap on the button or the view from which you have dragged the control to Exit, the method in your AVC gets called :)

In AVC's method you can access the BVC instance because now you have the access to segue instance :) remember prepareForSegue method for direct segues, this is similar to that for unwind segue :)

let childVC : SecondViewController = segue.sourceViewController as! SecondViewController
print(childVC.name)
self.dismissViewControllerAnimated(true, completion: nil) 

Notice the usage of "segue.sourceViewController" once you have the acces to BVC access its data :)

Hope my answer helped :)

Sandeep Bhandari
  • 19,999
  • 5
  • 45
  • 78
  • Thanks! Shouldn't var myParent be of type AVC, instead of letsCallParent, like this myParent:AVC? ? – Shivam Bhalla Apr 22 '16 at 07:49
  • Also, in my case since no method of the AVC is called when I dismiss BVC, where do I call amDoneHere() to access it ? – Shivam Bhalla Apr 22 '16 at 07:51
  • @shivam-bhalla : As per your question Shouldn't var myParent be of type AVC ? NOPE. BVC does not need to know that its parent is of type AVC :) That will lead to close coupling :) That means if any other viewcontroller lets say CVC presents BVC then setting your delegate myParent to AVC will lead to error :) you dont want want delcare a seperate delegate for each view controller isnt it buddy :) – Sandeep Bhandari Apr 22 '16 at 07:57
  • As per your second question :) no method of the AVC is called when I dismiss BVC, where do I call amDoneHere() ? :) You dont call amDoneHere() on AVC buddy :) you call it in BVC on myParent variable :) that will in turn trogger the code in AVC :) now where to call it depends on you program logic :) assume you have a button in BVC called dismiss and when you tap on it you have to dismiss BVC :) in that case inside the IBAction of thet method simply call parent.amDoneHere("Hi am Done here") – Sandeep Bhandari Apr 22 '16 at 08:00
  • In case you still have a doubt feel free to comment buddy :) – Sandeep Bhandari Apr 22 '16 at 08:00
  • how did u make protocol for system VC, suck as : AVPlayerViewController??? – famfamfam Apr 01 '21 at 13:37
  • The delegate should be `weak`, otherwise this will create a retention cycle. Plus, try to stick to the naming conventions: a protocol's name should use an upper CamelCase naming style. Also, it should preferably end with the word `...Delegate`. And example would be: `ChildTaskDelegate`. – Starsky May 06 '22 at 10:07
4

Issue Explanation

As u noticed that when presenting OverCurrentContext, viewWillAppear will not be called on dismiss.

Why ?

viewWillAppear will be called whenever u back to your view (in case that the view is already disappeared). When u present a new view using OverCurrentContext, the main view is still appeared and u present a new one over it or over part of it ! Popup effect !

Because of this logic, viewWillAppear will not be called when u dismiss the OverCurrentContext view and u have to handle it manually using any way like @Sandeep did above.

Community
  • 1
  • 1
Essam Fahmi
  • 1,920
  • 24
  • 31