viewWillAppear getting called before viewDidDisappear of another controller gets finished - objective-c

I have 2 view controllers say VC-1, VC-2. I have VC-2 displayed over VC-1 through navigation stack. VC-1 has textView and VC-2 has webView. Now I need to update the VC-1's content as soon as VC-2 is popped off. Hence I am using viewDidDisappear method of VC-2 to set the content and using that in viewWillAppear of VC-1 to update the textView (VC-1's content). But before viewDidDisappear finishes itself viewWillAppear of VC-1 gets executed and the content is not updated. I have checked this by NSLogging. viewDidDisappear has some file reading stuff so I guess that is causing the problem. How can I make the WillAppear(of VC-1) to get called after DidDisappear(VC-2) gets finished?

-viewWillAppear: is called before your view comes on screen at all. -viewDidDisappear: is called after your view is wholly gone from the screen. Therefore on any sort of animated transition, e.g. a navigation stack pop/push, the incoming VC's -viewWillAppear: will necessarily be called before the departing VC's -viewDidDisappear: is called. This is perfectly correct.
You should probably take the work you're doing in -viewDidDisappear: and move that to -viewWillDisappear: instead.

Related

tvOS - dismissing to top of storyboard causes all intermediate screens to -viewWillAppear/Disappear

I am several levels deep in a storyboard and want to unroll everything all the way back to the first screen. Fortunately, there are APIs designed to do exactly this:
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
[topController dismissViewControllerAnimated:NO completion:nil];
However, this method seems to "unroll" the view stack one by one, causing each view between my current position and the first screen to briefly invoke viewWillAppear, viewDidAppear, viewWillDisappear, and viewDidDisappear. This causes a cacophony of activity in my app, as most of the intermediate screens do interesting things when they appear. I can set breakpoints in Xcode and watch these methods get invoked in reverse order back to the main screen.
I need a way to pop back to the start of the storyboard without causing every screen along the path to light up and do work.
If this means I cannot use viewWillAppear for this purpose any more, I am willing to switch to a replacement method as long as one exists.
This is expected behaviour. I assume you're presenting the layers of views with presentViewController... calls on each previous view.
You should look at using a UINavigationController as your top level view instead. Then you can just call popToRootViewControllerAnimated: when you want to go all the way back.

UINavigationController animates on push but not when tapping back button

I'm doing a storyboard segue when tapping a navigation bar button item, from view controller A to view controller B, and it works fine with a push animation. But when I tap the back button (no custom code) the previous view (A) just pops into place without the sliding animation. The same happens when I do a [self.navigationController popViewControllerAnimated:YES], i.e. there's no animation. I've made sure that I'm only popping it once.
This has been tested in the simulator as well as on a device.
I suspect it has something to do with what happens when view controller B is being unloaded or something similar, but I can't put my finger on it. I am handling an ABRecordRef property in B, but I have tried to be careful to call CFRetain and CFRelease in the setter when appropriate. I'm doing calls to outlets in various setters and getters but again have been careful to only do it if the view is loaded in case that would cause the view to reload after being unloaded. No success.
Finally did a log in B's viewWillDisappear, and animated is set to false. Why's that?
I don't know what to do next, my segue has the "push" style in the storyboard.

addSubview: re-writes the navigation stack?

I'm working on a app which uses the controller containment pattern as described in the View Controller documentation in the iOS SDK.
I've written the controller container, and it works great. My controller is basically containing two sub views and it displays them both at the same time, sliding one over the other depending on what the user is doing. Works wonderful.
Now, I want to use this container controller in a navigation view. This is to get push segues to work. In effect, from my contained controllers, I want to be able to use the navigation stack, push a new controller on, and pop when the user is done.
However, I have noticed that if the navigation view is instantiated with my container controller as the root container, things fall apart.
In particular, I have noticed this:
In the iOS documentation, container controllers call addChildController: and then addSubview:. This seems to break the navigation stack, as the push segue does not work - it behaves like modal. I believe it does this because addSubview resets the navigation stack.
I confirmed this by replacing addChildController and addSubview with [self.navigationController pushViewController...]. I confirmed it is a problem with addSubview because I can reproduce the issue when I omit the call to addChildController.
When I do this, the navigation stack works properly. But of course, my container controller does not, as only the "most recently pushed" controller is visible.
I'm doing this because in my contained controllers, I want to push a new controller onto the stack, and when the user is done, I want to "pop" the stack, without reloading the "previous controller".
Using a modal segue reloads the previous controller; using a push controller does not.
I cannot find any documentation on the behavior of addSubview and it's effect on the navigation stack.
Thank you in advance for any light you guys can shed!
I'm having a bit of trouble completely understanding what you are doing, but I think that what you want to do is exactly what I'm doing.
I have a UINavigationController that has as its rootView a container UIViewController. That controller adds children per the normal methods. One of those children views pushes other views that may get popped.
One of those pushed views COULD message the appDelegate and make itself the rootViewController if it wanted to. In general, as long as you keep a strong reference to a view controller, you can remove it from whoever 'owns' it, and muck around with the navigationControllers viewControllers array to your hearts content.

View not updating before automatic Segue away from itself

Essentially I have a view controller where the user picks from three choices. Once the user chooses something, the view segues away to another view controller that displays some information regarding their choice for about 5 seconds and then segues back to original view controller automatically where the User must make more choices... (its basically a loop until something is accomplished).
The problem I am having is when the User touches their option, it seems to just segue back to itself without ever displaying the intermediary screen. I added a sleep(5); to the viewDidLoad but all that causes it to do is pause on the original choice screen for 5 seconds before segueing to itself. I also put in an NSLog in just to make sure it was actually using the new controller, which it is indeed.
I didn't include code since its so trivial. viewDidLoad on the new controller, has sleep(5) and the call to segue back to the original view controller.
I solved the problem by moving the code to viewDidAppear. Should have done that from the beginning honestly, just didn't think it through enough I guess.

UITextView: Must I always resignFirstResponder?

Must I always resignFirstResponder for a UITextView? Or, will this happen automatically when its view controller disappears?
I'm asking because I'm having an issue similar to iPhone Objective-C: Keyboard won't hide with resignFirstResponder, sometimes, where the keyboard stays up even when the nav controller pushes and pops other view controllers. The keyboard works, and when I hit done, it unfocuses the UITextView (i.e., the cursor disappears), but the keyboard stays up.
I never found out why this is happening, but maybe it's due to not doing resignFirstResponder before pushing another view controller, but I thought it was optional?
At a total guess, the UITextView has a reference to the view controller (as its delegate) but does not retain it. When you go to the next screen, the controller is dealloced and then the UITextView (which has perhaps been retained by something else) tries to call back to the dealloced controller and crashes. When you call resignFirstResponder, you reverse the order this happens, and therefore no crash.
The way round this to add a textView.delegate = nil call in your view controller's dealloc method - obviously put it before you release the text view.
The contract between a UITextView and it's delegate says that the delegate will send -resignFirstResponder when the text view is done editing. This informs the framework that the view is done editing, fires the events relating to that (willEndEditing and didEndEditing), and allows other parts of the responder hierarchy to react accordingly. Failing to do so might work, but it's not following the contract (that's all a protocol is) it agreed to.
I don't think you have to because the Xcode Sample UICatalog UITextField doesn't call resignFirstResponder before the TextViewController is popped.
The reason the keyboard got stuck for me is that I was having the same view controller present two view controllers modally at the same time, one after the other. UIKit didn't like that.
Calling resignFirstResponder makes sure that the text property contains the actual text shown in the control.
Depending on the state this is not always necessary, but if your controls have resigned first responder, you know that you're working with valid data.