1

I would like to process code when a ViewController is no longer visible due to presenting a new ViewController.

I cannot use ViewWillDisappear etc since the controller is not technically ever dismissed from the stack - you just can't see it.

What process can I use so that code runs when the controller is no longer visible (i.e. topmost) and when it becomes visible again?

EDIT: Seems some confusion here - not sure why. I have a viewcontroller. I use the following code to present another controller

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navController = storyboard.instantiateViewControllerWithIdentifier("NavController") as! UINavigationController
let thisController = navController.viewControllers[0] as! MyController
self.presentViewController(navController, animated: true, completion: nil)

This controller does not trigger a viewWillDisappear on the previous controller since the previous view is not removed - just hidden.

I need to process code when this view is hidden (i.e. not visible) and, more importantly, process code when it becomes visible again.

RobertyBob
  • 803
  • 1
  • 8
  • 20
  • elaborate more here. – KKRocks Nov 04 '16 at 12:41
  • please provide more specifics on what kind of task you want to keep doing while the presenting controller is covered with a different VC. Also, elaborate on why viewDidDisappear doesn't do the trick – Sergey Katranuk Nov 04 '16 at 12:43
  • not sure how to elaborate really - i present a view controller, that covers the previous controller, i need the previous controller to process code when that happens (actually i can deal with that in some way) - the issue is then how to process code when the original controller becomes visible again – RobertyBob Nov 04 '16 at 12:45
  • can you put screenshot here ? – KKRocks Nov 04 '16 at 12:46
  • @serghei - viewDid/WillDisappear only triggers if the controller is removed from the hierarchy/stack - it is not - it just has a controller presented over it – RobertyBob Nov 04 '16 at 12:46
  • screenshot? good grief – RobertyBob Nov 04 '16 at 12:46
  • @RobertyBob as far as I know it does trigger viewDidDisappear. Just checked – Sergey Katranuk Nov 04 '16 at 12:54
  • at the very least, if you want to just do something once the presenting controller is covered, implement that logic in the completion block of the present function: `self.presentViewController(navController, animated: true, completion: { // your logic here })` – Sergey Katranuk Nov 04 '16 at 13:01
  • 1
    Ahh are you presenting the new `UIViewController` with a `UIModalPresentationOverCurrentContext`? – Rikh Nov 04 '16 at 13:06
  • @serghei - thx - nothing triggering here when view controller covered by presented one - will try the completion method - what process can be used when it becomes visible again? – RobertyBob Nov 04 '16 at 13:07
  • if viewDidAppear on the presenting controller isn't called, then you could implement some delegation between these 2 controllers. So that the presented controller will inform the starting controller that he has finished doing his job and will disappear. if you're not familiar with how delegation works, I can provide some sample code – Sergey Katranuk Nov 04 '16 at 13:36
  • also, if @Rikh was right and you have a `UIModalPresentationOverCurrentContext` presentation style, then this answer might help you out http://stackoverflow.com/questions/30474034/view-controller-lifecycle-on-uimodalpresentationovercurrentcontext although it's a bit more granular and complex than what I proposed – Sergey Katranuk Nov 04 '16 at 13:39
  • @serghei - some code for that would be great thx – RobertyBob Nov 04 '16 at 13:42
  • @Rikh - not sure what the modal presentation is but the presented controller is just a normal view – RobertyBob Nov 04 '16 at 13:46
  • I've posted it as an answer – Sergey Katranuk Nov 04 '16 at 14:00
  • `UIModalPresentationOverCurrentContext` is the way the new view controller will appear. A simple test to check if thats the case would be to set the `NavController` that you are using to have a clear background color. If you do this and present the `NavController` **and** you can still view the first `UIViewController` below your `NavController` content. Then you are using `UIModalPresentationOverCurrentContext` and that is why the `viewDidDisappear` isn't called. Have a look at the answer @SergheiCatraniuc linked in his comment. – Rikh Nov 04 '16 at 15:41
  • @rikh - can you add this as an answer so i can credit it - thx – RobertyBob Nov 04 '16 at 16:17
  • Sure! Just did. – Rikh Nov 04 '16 at 17:40

3 Answers3

1

EDIT: This is in Swift 3, you can adjust your method accordingly if you're using an older version of Swift

If you won't be able to figure out why viewDidAppear and viewDidDisappear are not called, here's a workaround

protocol MyControllerDelegate {
    func myControllerWillDismiss()
}

class MyController: UIViewController {
    var delegate: MyControllerDelegate?

// your controller logic here

    func dismiss() { // call this method when you want to dismiss your view controller

        // inform delegate on dismiss that you're about to dismiss
        delegate?.myControllerWillDismiss()
        dismiss(animated: true, completion: nil)
    }
}

class PresentingController: UIViewController, MyControllerDelegate  {
    func functionInWhichYouPresentMyController() {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let navController = storyboard.instantiateViewController(withIdentifier: "NavController") as! UINavigationController
        let thisController = navController.viewControllers[0] as! MyController
        thisController.delegate = self // assign self as delegate
        present(navController, animated: true, completion: {
            // place your code that you want executed when it disappears here
        })
    }

    func myControllerWillDismiss() {
        // this method will be called now when MyController will dismiss
        // place your code that you want executed when it re-appears here
    }
}
Sergey Katranuk
  • 1,162
  • 1
  • 13
  • 23
  • many thanks - would it also be possible for you to post the presenting code you say works with the presenting controller viewDidDisappear? the code I'm using in Swift2 is in my original post. dealing with the appear/disappear would save hours of coding in relation to adding delegates all over the place so would be good to check that first - thx – RobertyBob Nov 04 '16 at 15:41
  • `let anotherVC = self.storyboard?.instantiateInitialViewController() let navController = UINavigationController(rootViewController: anotherVC!) self.presentViewController(navController, animated: true, completion: nil)` – Sergey Katranuk Nov 04 '16 at 15:51
  • 1
    You might have set the `modalPresentationStyle` on your UINavigationController in the storyboard to `UIModalPresentationStyle.OverCurrentContext` as @Rikh has mentioned earlier. I tested that and in that case indeed you don't get those methods calle – Sergey Katranuk Nov 04 '16 at 15:55
  • thx for clearing that up - both potential controllers have presentation style set to Full Screen - wait sry one of them had it programatically changed to Custom.... – RobertyBob Nov 04 '16 at 16:00
  • glad you figured it out :) – Sergey Katranuk Nov 04 '16 at 16:34
1

When presenting a UIViewController if the presentation style has been set to UIModalPresentationOverCurrentContext it doesn't call the viewWillDisappear and related methods as the view never disappears or gets hidden.

A simple test to check if thats the case would be to set the NavController that you are using to have a clear background color. If you do this and present the NavController and you can still view the first UIViewController below your NavController content. Then you are using UIModalPresentationOverCurrentContext and that is why the viewDidDisappear isn't called.

Have a look at the answer referenced by Serghei Catraniuc (https://stackoverflow.com/a/30787112/4539192).

Community
  • 1
  • 1
Rikh
  • 4,078
  • 3
  • 15
  • 35
0

Firstly, thanks to Serghei for his time in helping work through this.

To clarify, both my potential presented controllers were set to Full Screen presentation style in the storyboard, however one was being set to Custom via a piece of pasted code dealing with the presentation. I can't find the error with the other.

However, if I force a presentation style of Full Screen as part of the presenting process then all is ok.

Hopefully my frustrating afternoon can help to save someone else's - always try to understand the implications and processes involved in pasted snippets.

RobertyBob
  • 803
  • 1
  • 8
  • 20