UIViewTableCell didSelectRowAtIndexPath is calling but not pushing a view controller - iphone

so im having a UIViewController view with a UITableView.
So the UIViewController class name is SelectionScreen.
The UITableView class name is SelectionScreenTable.
Picture:
http://img717.imageshack.us/i/screenshot20100609atpm0.png/
I have declared a UITableView *selectionTable in SelectionScreen class and connected it to the xib file of the SelectionScreen
what the problem is , is that when i click a row in the table,it stays selected as highlighted blue, it calls the didSelectRowAtIndexPath (checked with NSLog) but not pushing a new view which is called(GraphView).
This is the code which i use to call the new controller WHICH WORKS with a normal button
GraphView *aSelectionScreenViewController = [[GraphView alloc]
initWithNibName:#"GraphView"
bundle:nil];
[self presentModalViewController:aSelectionScreenViewController animated: YES];
[aSelectionScreenViewController release];
I searched around and found that I need to set a delegate for the table in the UITableView class itself on the viewload
tableview.delegate = self;
or
self.tableview.delegate = self;
But it was not working. the controller was still not being pushed, and yes i have checked the controller is not nil as i tried it with a simple button.
So i was thinking whether i should set the delegate of the UITableView at the UIViewController instead, so i tried this code
selectionTable.delegate = selectionTable.self;
but obviously it did not work =\, it messed up the whole UITableView and caused all the cells to be its predefined settings.
So does anybody have any idea on how i can get it to work.

It's a bit hard to get the full picture here, but I can try some hints.
The outlets seem to be correctly connected from the screenshot, although Selection Screen Table could probably be called Selection Screen Table Controller and the class name should be SelectionScreenTableController for less confusion.
I think the problem could be that the method presentModalViewController: must be called on an active view controller to work.
From what I can tell you have three view controllers, a SelectionScreenTableController, a GraphViewController, and then there must also be some kind of main controller, probably SelectionScreenController.
The SelectionScreenController is the active view controller, so that must be the one to have sent the presentModalViewController: message.
There are several ways you could solve this. The quick fix would be to make an outlet in SelectionScreenTableController called selectionScreenController and link it to File's Owner in the nib file (assuming your SelectionScreen class is in fact a view controller), then call:
[selectionScreenController
presentModalViewController:aSelectionScreenViewController
animated: YES];
instead in your current listing of didSelectRowAtIndexPath:

Hey guys, i solved it, in the screenshot
http://img717.imageshack.us/i/screenshot20100609atpm0.png/
The SelectionScreenTable controller in the XIB of SelectionScreen, the view outlet was not connected to the XIB in the SelectionScreen XIB, so i guess it wasn't properly configured.

i solved it instead of using
presentModalViewController.
i used an animation to bring in the view instead
More info in the link below
http://www.iphonedevsdk.com/forum/iphone-sdk-development/13427-uiview-slide-transition.html

Related

iPhone UINavigation Issue - nested push animation can result in corrupted navigation bar

I keep getting the following errors:
2011-04-02 14:55:23.350 AppName[42430:207] nested push animation can result in corrupted navigation bar
2011-04-02 14:55:23.352 AppName[42430:207] nested push animation can result in corrupted navigation bar
2011-04-02 14:55:23.729 AppName[42430:207] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
2011-04-02 14:55:23.729 AppName[42430:207] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
Here is what I am doing. From a view controller, I call the following when a certain button is pushed:
EventsViewController *viewController = [[EventsViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
navController.navigationBar.tintColor = [UIColor blackColor];
[self presentModalViewController:navController animated:YES];
[viewController release];
[navController release];
Then, if a certain button is pushed in EventsController, I call:
SingleEventViewController *viewController = [[SingleEventViewController alloc] initWithEvent:[currentEvents objectAtIndex:indexPath.row]];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
Then, if a certain button is pushed in SingleEventViewController, I call:
EventMapView* viewController = [[EventMapView alloc] initWithCoordinates];
[[self navigationController] pushViewController:viewController animated:YES];
[viewController release];
So yea, it's obvious that there's nested push animations, but isn't this the right way to go about it? I checked out Apple's DrillDownSave code and this appears to be how they're doing it. Does it matter that I use init methods instead of viewDidLoad methods?
Calling pushViewController before viewDidAppear is unsafe.
ACCIDENTLY TRIGGERING THE SAME SEGUE TWICE
Once in code, and once from interface builder, but both at the same time...
I was getting the same error as the rest of you. Only my problem was I was accidentally firing the same segue, twice. Once from interface builder, and once from within my code.
I have a UITableView. When a cell is selected, a segue in interface builder fires. Heres my problem, I had the segue set up to be directly fired off clicking the CELL ITSELf, inside interface builder, then in my code, I had under didSelectRowAtIndexPath, code that would fire that same segue... like so...
[self performSegueWithIdentifier:#"MySegue" sender:tableView];
That means when didSelectRowAtIndexPath gets called because a row was selected, it fires the segue with the above line of code. Then interface builder, also triggers the segue, because its connected directly to the cell object in interface builder. To stop interface builder from directly firing the segue. You have to connect the segue from the top of the view controller, not nested down inside coming off of the cell itself.
So if you are having this problem for the same reason as me, that is, you are calling the same segue twice, you can fix this by unlinking the connection from the CELL DIRECTLY, to your segue, and having the segue connection originate at the top of the table hierarchy in IB, rather than nested inside the cell. Connect the segue from you View Controller itself, to the segue. If you have done this correct, when you select the segue, it should highlight the ENTIRE view it is coming from, not just the cell.
Now Apples documentation states thus under the performSegueWithIdentifier:sender: reference:
Apps normally do not need to trigger segues directly. Instead, you configure an object in Interface Builder associated with the view controller, such as a control embedded in its view hierarchy, to trigger the segue. However, you can call this method to trigger a segue programmatically, perhaps in response to some action that cannot be specified in the storyboard resource file. For example, you might call it from a custom action handler used to process shake or accelerometer events.
In my case, I have a search button for my UITableView, and whether the segue is called when the search results table is present, or the normal table view is present, had to be determined. So I needed to trigger the segue directly.
So remove the embedded control from interface builder, and just stick it on the view controller itself, then trigger the segue in your code!
Now, no more double segues! And no more errors.
I had the same problem / error message as you did just now, was looking for a solution and ended up at this thread, however, for me I found that the solution is actually having only one animated:YES when doing a nested push (I put animated:YES only for the final push), hope this helps
cheers.
I've figured it out. Apparently if you call -pushViewController from outside of the -didSelectRowAtIndexPath method of a UITableViewDelegate, it doesn't work. Moving the call into that function worked. Weird.
I happened upon this same problem that resulted from a button in a nib being connected to two different actions. It tried loading both view controllers, thereby corrupting the stack.
What do you mean when you say you use init methods instead of viewDidLoad methods?
If you're pushing a new view controller before the old push has bad a chance to be actioned, you will get this sort of error. So putting certain code into init and doing things prematurely could certainly get you the error being reported.
At the point where init is being run on a view controller, the view hasn't been loaded yet!
Um I had this issue, and Im new to the whole iOS dev scene. But after looking at my connections inspector (with file's owner) in the interface builder i saw that as I had copied a button it had the previous buttons method assigned to it as well as the new method I had created. I guess that was where the nested aspect of my problem came from, as it was executing 2 different methods both of which pushed a view onto the Nav Controller. I know this has already been answered but I figured I would put this up just in case anyone else had a silly mistake like mine.
This has already been answered, but I thought this might help others as I got the same error but without using table views. I finally figured out the problem.
I had an existing button whose IBAction invoked a pushViewController. I had created a new button by copying the existing button. The new button also had an action that invoked pushViewController. When the new button was tapped (touch up inside) and the view controller was pushed, I got this error. I deleted the new button, created it from scratch, bound it to the existing outlets and actions, and the error went away.
Ran into the same problem. In my case I was missing a break in the switch statement so two segues were fired at the same time. Easy fix for me.
My problem had to do with the keyboard being active.
This was caused for me by pushing a ViewController from a textField's delegate method:
-(void)textFieldDidBeginEditing:(UITextField *)textField{
FilterLocationViewController *destViewController = (FilterLocationViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"FilterLocationViewController"];
[self.navigationController pushViewController:destViewController animated:YES];
}
By changing the code to this:
-(void)textFieldDidBeginEditing:(UITextField *)textField{
[_textFieldLocation resignFirstResponder]; //adding this line
FilterLocationViewController *destViewController = (FilterLocationViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"FilterLocationViewController"];
[self.navigationController pushViewController:destViewController animated:YES];
}
(adding the line [textField resignFirstResponder];) the problem went away.
Basically the lesson is that you shouldn't modify the navigationController stack if the keyboard is out.
Recently, I've faced the same problem. The reason was: -I was trying to pop view controller twice by mistake. you can check this crash by setting breakpoints on push and pop View controllers
1) Perhaps you could try passing the necessary variables as properties before pushing the UIViewController rather than using the init methods with parameters. Most likely you will need these parameters beyond your init method anyway.
Also, in your initWithCoordinates: method you are missing the parameters. Possibly your custom init methods are a part of the problem.
2) Just because you mentioned viewDidLoad -- this method is for initialization after a view has loaded . If you create the UIViewController in code, as it seems you do, you should use loadView to set up your subviews.
This was happening for me because of my UIControlEvents
[button addTarget:self action:#selector(callSecondView) forControlEvents:UIControlEventAllTouchEvents];
I had to change the UIControlEventAllTouchEvents to UIControlEventTouchUpInside or however you want your button to work if you had the issue because of a UIButton call.
My Solution was
[self performSelector:#selector(moveTo) withObject:nil
afterDelay:0.5];
Don't know about other's. I think most of the People using StoryBoard is facing such Problem. I am using XIB.
In my case The Problem Was, when I was moving to another view using push,
I was also using
[self.navigationController popViewControllerAnimated:YES];
in the ViewWillDisappear of the current View at the same time. Just remove it and it works fine.
I was using POP, because of the requirement and the Flow.
The Hierarchy was 1 -> 2 ->3
I was on view 2 and wanted to move to view 3. In that case I encountered this error.
In my case I was both setting the push segue from the storyboard and programatically. Hopefully that'll help anyone
I had this error message too, and the navigation bar and navigation controller transitions were weird. My setup was a bunch of Navigation Controllers embedded in a Tab bar Controller. The problem was that I didn't call super.viewDidLoad() in my Tab bar Controller implementation of viewDidLoad.
Calling super is something the docs clearly point out that you should do when overriding viewDidLoad, and I learned this the hard way.
Maybe this can help someone else too!
I know that this was answered, but it could help others.
I had the same problem, but it was caused because I was using a bad event for an info button.
I was using "UIControlEventAllTouchEvents" and this generated two push of the same view into the navigation controller. The correct event was "UIControlEventTouchUpInside". I'm new to iOS.
This resolves the problem:
https://github.com/nexuspod/SafeTransition
If you push (or pop) a view controller with animation(animated:YES) it doesn't complete right away, and bad things happen if you do another push or pop before the animation completes.
To reproduce this bug, try pushing or popping two view controllers at the same time. Example:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIViewController *vc = [[UIViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
You will receive this error:
2014-07-03 11:54:25.051 Demo[2840:60b] nested push animation can
result in corrupted navigation bar 2014-07-03 11:54:25.406
Demo[2840:60b] Finishing up a navigation transition in an unexpected
state. Navigation Bar subview tree might get corrupted.
Just add the code files into your project and makes your navigation controller as a subclass of APBaseNavigationController, and you'll be good to do.
Just to complete the list, here is another reason which can cause "nested push animation can result in corrupted navigation bar":
I did setup several NavigationController within a TabBarController and set
the selectedIndex within the storyboard Identifiy Properties. After moving active Tab to Code error disappeared.

How to load more than one ViewController when using TabBarController?

I have a TabBarController with 7 Custom ViewControllers and what i am trying to do is have the TabBarController on startup load the first ViewController in its array as well as a ViewController in one of the other tabs.
As far as i understand it the viewDidLoad method for the ViewController's is only called for that tab when it is first selected. Is there a way to force the TabBarController to call a ViewController viewDidLoad method even if its not active?
thx
Just reference the ViewController view:
[myViewController view]
If myViewController's view is nil, then it will be loaded.
Note that even if this approach is working, your app will be affected by the view loading/unloading mechanism which is controlled by the internal run loop logic and not by your app, while the view controller "internal logic" should be initialized by the initWithNib: method which is completely under your control. But this is just a suggestion to avoid strange bugs, anyway the solution proposed is working.
This technique seems to work pretty good. I have an app with a UITabBarController at the bottom with 5 buttons in it. When the user clicks the 3rd button, the viewDidLoad for that view took 5 seconds to do stuff so I used this technique to cause its viewDidLoad to get called when the app starts. I don't want the 3rd view to be displayed; just to be initialized so it shows up instantly when clicked.
I had to subclass the UITabBarController to something like FoohBarController, then in it's viewDidLoad I made a background thread do this:
{
// get a pointer to the 3rd item in the tab bar (0 based)
UINavigationController *navcon = [self.viewControllers objectAtIndex:2];
// get a pointer to the viewController I want to init
CalendarViewController *calendar = [navcon.viewControllers objectAtIndex:0];
// Just ask for the view. This will force the view to load and to initialize
UIView *v = calendar.view;
v = nil; // to remove a compiler warning
}

presentModalViewController on parent viewcontroller

I have a viewcontroller, where I load subviews on. In those subviews I have a UIButton which will show a modalViewController. If I call the function on the main viewcontroller, I get the modal exactly in the middle as I want them to be, but if I call the exact same method in the view I've added as a subview the modal is presented somewhere on the right side of the screen. So now is my question: how can I present the modal on the super view instead? Or how do I put the modalview in center? Because the views I've added as subviews contains data which the modalpopup needs.
This is how I present the modal:
MapViewer *map = [[MapViewer alloc] init];
map.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:map animated:YES];
[map release];
Hope somebody can help me with this.
Thanks in advance!
Edit:
Maybe useful to be more clear:
AppDelegate.m
-> MainWindow.m
-> OtherViewController.m
So I add an x amount of OtherViewControllers as subviews to MainWindow. The OtherViewController contains the function mentioned above. But the map needs to be displayed as a modal on the MainWindow, and not on the OtherViewController so it gets nicely centered etc.
One thing you might do is set the target of the UIButton object to the main view controller using setTarget:action: method.
Ok I've managed to get it working using the notificationcenter so I can call a method on the MainWindow from other views. So if anyone is asking the same question, have a look at the notificationcenter :D

UIViewController presentModalViewController: animated: doing nothing?

I recently started a project, using Apple's Utility Application example project. In the example project, there's an info button that shows an instance of FlipSideView. If you know the Weather.app, you know what the button acts like.
I then changed the MainWindow.xib to contain a scrollview in the middle of the window and a page-control view at the bottom of the window (again, like the Weather.app). The scrollview gets filled with instances of MainView. When I then clicked the info button, the FlipSideView would show, but only in the area that was previously filled by the MainView instance – this means that the page-control view on the bottom of the page still showed when the FlipSideView instance got loaded.
So, I thought that I would simply add a UIViewController for the top-most window, which is the one declared inside the AppDelegate created along side with the project. So, I created a subclass of UIViewController, put an instance of it inside MainWindow.xib and connected it's view outlet to the UIWindow declared as window inside the app delegate. I also changed the button's action, so that it know sends a message to the MainWindowController instance. The message does get sent (I checked with NSLog() statements), but the FlipSideView doesn't get shown. Here's the relevant (?) code:
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"FlipsideView" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
[controller release];
Why's this not working from inside of MainWindowController, but the exact same code is working from inside of MainViewController? I've uploaded the entire project here for you to be able to see the whole thing.
Thanks for help!
-- Ry
EDIT: I think it might be related to me attaching the UIViewController's view outlet to an UIWindow instance. I now connect it to a UIView, and it's working perfectly well.
For the record, the answer has been added in the question. Ryyst said:
I think it might be related to me
attaching the UIViewController's view
outlet to an UIWindow instance. I now
connect it to a UIView, and it's
working perfectly well.

iPhone viewWillAppear not firing

I've read numerous posts about people having problems with viewWillAppear when you do not create your view hierarchy just right. My problem is I can't figure out what that means.
If I create a RootViewController and call addSubView on that controller, I would expect the added view(s) to be wired up for viewWillAppear events.
Does anyone have an example of a complex programmatic view hierarchy that successfully receives viewWillAppear events at every level?
Apple's Docs state:
Warning: If the view belonging to a view controller is added to a view hierarchy directly, the view controller will not receive this message. If you insert or add a view to the view hierarchy, and it has a view controller, you should send the associated view controller this message directly. Failing to send the view controller this message will prevent any associated animation from being displayed.
The problem is that they don't describe how to do this. What does "directly" mean? How do you "indirectly" add a view?
I am fairly new to Cocoa and iPhone so it would be nice if there were useful examples from Apple besides the basic Hello World crap.
If you use a navigation controller and set its delegate, then the view{Will,Did}{Appear,Disappear} methods are not invoked.
You need to use the navigation controller delegate methods instead:
navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:
I've run into this same problem. Just send a viewWillAppear message to your view controller before you add it as a subview. (There is one BOOL parameter which tells the view controller if it's being animated to appear or not.)
[myViewController viewWillAppear:NO];
Look at RootViewController.m in the Metronome example.
(I actually found Apple's example projects great. There's a LOT more than HelloWorld ;)
I finally found a solution for this THAT WORKS!
UINavigationControllerDelegate
I think the gist of it is to set your nav control's delegate to the viewcontroller it is in, and implement UINavigationControllerDelegate and it's two methods. Brilliant! I'm so excited i finally found a solution!
Thanks iOS 13.
ViewWillDisappear, ViewDidDisappear, ViewWillAppear and
ViewDidAppear won't get called on a presenting view controller on
iOS 13 which uses a new modal presentation that doesn't cover the
whole screen.
Credits are going to Arek Holko. He really saved my day.
I just had the same issue. In my application I have 2 navigation controllers and pushing the same view controller in each of them worked in one case and not in the other. I mean that when pushing the exact same view controller in the first UINavigationController, viewWillAppear was called but not when pushed in the second navigation controller.
Then I came across this post UINavigationController should call viewWillAppear/viewWillDisappear methods
And realized that my second navigation controller did redefine viewWillAppear. Screening the code showed that I was not calling
[super viewWillAppear:animated];
I added it and it worked !
The documentation says:
If you override this method, you must call super at some point in your implementation.
I've been using a navigation controller. When I want to either descend to another level of data or show my custom view I use the following:
[self.navigationController pushViewController:<view> animated:<BOOL>];
When I do this, I do get the viewWillAppear function to fire. I suppose this qualifies as "indirect" because I'm not calling the actual addSubView method myself. I don't know if this is 100% applicable to your application since I can't tell if you're using a navigation controller, but maybe it will provide a clue.
Firstly, the tab bar should be at the root level, ie, added to the window, as stated in the Apple documentation. This is key for correct behavior.
Secondly, you can use UITabBarDelegate / UINavigationBarDelegate to forward the notifications on manually, but I found that to get the whole hierarchy of view calls to work correctly, all I had to do was manually call
[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];
and
[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];
.. just ONCE before setting up the view controllers on the respective controller (right after allocation). From then on, it correctly called these methods on its child view controllers.
My hierarchy is like this:
window
UITabBarController (subclass of)
UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
UINavigationController (subclass of)
UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods
Just calling the mentioned methods on the tab/nav controller the first time ensured that ALL the events were forwarded correctly. It stopped me needing to call them manually from the UINavigationBarDelegate / UITabBarControllerDelegate methods.
Sidenote:
Curiously, when it didn't work, the private method
- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController
.. which you can see from the callstack on a working implementation, usually calls the viewWill/Did.. methods but didn't until I performed the above (even though it was called).
I think it is VERY important that the UITabBarController is at window level though and the documents seem to back this up.
Hope that was clear(ish), happy to answer further questions.
As no answer is accepted and people (like I did) land here I give my variation. Though I am not sure that was the original problem. When the navigation controller is added as a subview to a another view you must call the viewWillAppear/Dissappear etc. methods yourself like this:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[subNavCntlr viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[subNavCntlr viewWillDisappear:animated];
}
Just to make the example complete. This code appears in my ViewController where I created and added the the navigation controller into a view that I placed on the view.
- (void)viewDidLoad {
// This is the root View Controller
rootTable *rootTableController = [[rootTable alloc]
initWithStyle:UITableViewStyleGrouped];
subNavCntlr = [[UINavigationController alloc]
initWithRootViewController:rootTableController];
[rootTableController release];
subNavCntlr.view.frame = subNavContainer.bounds;
[subNavContainer addSubview:subNavCntlr.view];
[super viewDidLoad];
}
the .h looks like this
#interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
IBOutlet UIView *subNavContainer;
UINavigationController *subNavCntlr;
}
#end
In the nib file I have the view and below this view I have a label a image and the container (another view) where i put the controller in. Here is how it looks. I had to scramble some things as this was work for a client.
Views are added "directly" by calling [view addSubview:subview].
Views are added "indirectly" by methods such as tab bars or nav bars that swap subviews.
Any time you call [view addSubview:subviewController.view], you should then call [subviewController viewWillAppear:NO] (or YES as your case may be).
I had this problem when I implemented my own custom root-view management system for a subscreen in a game. Manually adding the call to viewWillAppear cured my problem.
Correct way to do this is using UIViewController containment api.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UIViewController *viewController = ...;
[self addChildViewController:viewController];
[self.view addSubview:viewController.view];
[viewController didMoveToParentViewController:self];
}
I use this code for push and pop view controllers:
push:
[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];
pop:
[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];
.. and it works fine for me.
A very common mistake is as follows.
You have one view, UIView* a, and another one, UIView* b.
You add b to a as a subview.
If you try to call viewWillAppear in b, it will never be fired, because it is a subview of a
iOS 13 bit my app in the butt here. If you've noticed behavior change as of iOS 13 just set the following before you push it:
yourVC.modalPresentationStyle = UIModalPresentationFullScreen;
You may also need to set it in your .storyboard in the Attributes inspector (set Presentation to Full Screen).
This will make your app behave as it did in prior versions of iOS.
I'm not 100% sure on this, but I think that adding a view to the view hierarchy directly means calling -addSubview: on the view controller's view (e.g., [viewController.view addSubview:anotherViewController.view]) instead of pushing a new view controller onto the navigation controller's stack.
I think that adding a subview doesn't necessarily mean that the view will appear, so there is not an automatic call to the class's method that it will
I think what they mean "directly" is by hooking things up just the same way as the xcode "Navigation Application" template does, which sets the UINavigationController as the sole subview of the application's UIWindow.
Using that template is the only way I've been able to get the Will/Did/Appear/Disappear methods called on the object ViewControllers upon push/pops of those controllers in the UINavigationController. None of the other solutions in the answers here worked for me, including implementing them in the RootController and passing them through to the (child) NavigationController. Those functions (will/did/appear/disappear) were only called in my RootController upon showing/hiding the top-level VCs, my "login" and navigationVCs, not the sub-VCs in the navigation controller, so I had no opportunity to "pass them through" to the Nav VC.
I ended up using the UINavigationController's delegate functionality to look for the particular transitions that required follow-up functionality in my app, and that works, but it requires a bit more work in order to get both the disappear and appear functionality "simulated".
Also it's a matter of principle to get it to work after banging my head against this problem for hours today. Any working code snippets using a custom RootController and a child navigation VC would be much appreciated.
In case this helps anyone. I had a similar problem where my ViewWillAppear is not firing on a UITableViewController. After a lot of playing around, I realized that the problem was that the UINavigationController that is controlling my UITableView is not on the root view. Once I fix that, it is now working like a champ.
I just had this problem myself and it took me 3 full hours (2 of which googling) to fix it.
What turned out to help was to simply delete the app from the device/simulator, clean and then run again.
Hope that helps
[self.navigationController setDelegate:self];
Set the delegate to the root view controller.
In my case problem was with custom transition animation.
When set modalPresentationStyle = .custom viewWillAppear not called
in custom transition animation class need call methods:
beginAppearanceTransition and endAppearanceTransition
For Swift. First create the protocol to call what you wanted to call in viewWillAppear
protocol MyViewWillAppearProtocol{func myViewWillAppear()}
Second, create the class
class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
updatedCntllr.myViewWillAppear()
}
}
}
Third, make the instance of ForceUpdateOnViewAppear to be the member of the appropriate class that have the access to the Navigation Controller and exists as long as Navigation controller exists. It may be for example the root view controller of the navigation controller or the class that creates or present it. Then assign the instance of ForceUpdateOnViewAppear to the Navigation Controller delegate property as early as possible.
In my case that was just a weird bug on the ios 12.1 emulator. Disappeared after launching on real device.
I have created a class that solves this problem.
Just set it as a delegate of your navigation controller, and implement simple one or two methods in your view controller - that will get called when the view is about to be shown or has been shown via NavigationController
Here's the GIST showing the code
ViewWillAppear is an override method of UIViewController class so adding a subView will not call viewWillAppear, but when you present, push , pop, show , setFront Or popToRootViewController from a viewController then viewWillAppear for presented viewController will get called.
My issue was that viewWillAppear was not called when unwinding from a segue. The answer was to put a call to viewWillAppear(true) in the unwind segue in the View Controller that you segueing back to
#IBAction func unwind(for unwindSegue: UIStoryboardSegue, ViewController subsequentVC: Any) {
viewWillAppear(true)
}
I'm not sure this is the same problem that I solved.
In some occasions, method doesn't executed with normal way such as "[self methodOne]".
Try
- (void)viewWillAppear:(BOOL)animated
{
[self performSelector:#selector(methodOne)
withObject:nil afterDelay:0];
}
You should only have 1 UIViewController active at any time. Any subviews you want to manipulate should be exactly that - subVIEWS - i.e. UIView.
I use a simlple technique for managing my view hierarchy and have yet to run into a problem since I started doing things this way. There are 2 key points:
a single UIViewController should be used to manage "a screen's worth"
of your app
use UINavigationController for changing views
What do I mean by "a screen's worth"? It's a bit vague on purpose, but generally it's a feature or section of your app. If you've got a few screens with the same background image but different overlays/popups etc., that should be 1 view controller and several child views. You should never find yourself working with 2 view controllers. Note you can still instantiate a UIView in one view controller and add it as a subview of another view controller if you want certain areas of the screen to be shown in multiple view controllers.
As for UINavigationController - this is your best friend! Turn off the navigation bar and specify NO for animated, and you have an excellent way of switching screens on demand. You can push and pop view controllers if they're in a hierarchy, or you can prepare an array of view controllers (including an array containing a single VC) and set it to be the view stack using setViewControllers. This gives you total freedom to change VC's, while gaining all the advantages of working within Apple's expected model and getting all events etc. fired properly.
Here's what I do every time when I start an app:
start from a window-based app
add a UINavigationController as the window's rootViewController
add whatever I want my first UIViewController to be as the rootViewController of the nav
controller
(note starting from window-based is just a personal preference - I like to construct things myself so I know exactly how they are built. It should work fine with view-based template)
All events fire correctly and basically life is good. You can then spend all your time writing the important bits of your app and not messing about trying to manually hack view hierarchies into shape.