dismisViewController leaks viewcontrollers when first responder set - iphone

In my simple navigation style iPhone app, when the user presses a button I am presenting a view controller V1 (modally) using presentViewController.
When the user presses another button this then presents another view controller V2 (modally) using presentViewController.
I then attempt to dismiss both in one go by calling dismissViewController on the root navigation controller and as expected they disappear from the screen :-) However when I log dealloc calls then I see nothing :-(
Through trial and error I tracked the issue down to the fact that in V1 I implement canBecomeFirstResponder == YES. If I change this to NO then everything deallocs properly. It's as though first responder is keeping a reference on the V1. However - when I present V2 I see V1 resign first responder. Indeed, if I don't ever present V2 then V1 will dealloc just fine/
Anyone seen anything like this or know what's going on? I'm on iOS7
[UPDATE: I'm using ARC and it's all in a very simple test app - so no delegates or strong references anywhere.)
Thanks.

why don't you dismiss V1 first before presenting V2? Then you would only have to dismiss V2 to go back to root.

Call poptorootviewcontroller on navigation controller before you dismiss it.

Related

Making a UITabView show the second level of a navigation controller by default

(Apologies for not being able to embed my images yet).
Using iOS storyboards, I have a UITabBarController with a UINavigation Controller/UITableView(1) embedded in it. This UITableView(1) then calls another UITableView(2):
What I'm trying to do is to make UITableView(2) appear when the Tab Bar is changed to that tab, and then have the UINavigationBar left arrow button exist to get back to UITableView(1).
The existing functionality I can think of which does this is the iPhone Mail app, where when you launch it you see your Inbox, and you can hit the left-arrow Mailboxes button to get back to your mail box list.
I've tried attaching the tab bar directly to UITableView(2) but it doesn't work as expected, there's no left arrow back button to get back to the previous view when the app is run.
I've also tried adding a navigation controller to that UITableView(2) and the Navigation controller correctly appears, but still without any back button:
Any suggestions as to what I'm doing wrong would be greatly appreciated, I'm fairly new with storyboards and it's difficult to find what to search to get this working.
If it's not possible with just storyboards themselves, is there some kind of automatic (non-visible) push to the 2nd UITableView I could do?
Thanks!
Nick.
This tutorial will definitely help you : http://maybelost.com/2011/10/tutorial-storyboard-in-xcode-4-2-with-navigation-controller-and-tabbar-controller-part1/
I ended up implementing it the following way, as I wanted to perform the majority of the work within storyboards.
I set up the storyboard with the tab bar embedding the UINavigationController, which contained UITableView(1) which then contained a custom segue to UITableView(2):
Then within the class associated with UITableView(1) I added this single line:
- (void)viewDidLoad {
[self performSegueWithIdentifier:#"campaigns" sender:self];
...
}
On load of the tab, the viewDidLoad of UITableView(1) instantly calls UITableView(2) without any kind of animation, showing the back button to UITableView(1), which is exactly what I wanted.
Thanks to those who responded!
You can implement the delegate method as below.
(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
In this method you can check for the tabBarController.selectedIndex or viewController object. This ensures the selection of correct tab , then push the controller having table 1, then push the controller having table 2.

UITabViewController, viewWillAppear does not invoked?

New to iOS, kindly bare if the question is very basic? When I press the tab button multiple times, it is not invoking viewWillAppear function? If I am wrong, then which function gets invoked, each time a tab button is pressed being on the same tabview?
You are correct, viewWillAppear is a little special, it is usually called automatically but in some cases including when you are adding a view controllers view manually (view addSubview:), and also when adding this as a view controller to a UITabViewController it doesn't get messaged.
This however is only for the root view, as you navigate (maybe with a navigation controller) back and forth, that root view's viewWillAppear will get triggered as some point.
In short, if you need to implement something in viewWillAppear in these cases, you should message it yourself when you know it's going to be presented. You can handle this case in your view controller, check out the following article about the matter:
http://www.touchthatfruit.com/viewwillappear-and-viewdidappear-not-being-ca
Good luck.

UINavigationController issue. viewWillDisappear/viewDidDisappear of view controllers not call on application startup

I am writing an application(for iPhone) that uses the UINavigationController to show different view via pushViewController. I am trying to push multiple UIViewController immediately upon application startup without user interaction. When an user open up the application, they will be looking on a screen with a navigation bar on the top that already have a back button.
The problem I am experiencing is that viewWillDisappear and viewDidDisappear of a ViewController does not always get call if another ViewController is pushed on top of it immediately upon application start up without user interaction. If the ViewController being pushed on top is activate by the user with a button click, then viewWillDisappear and viewDidDisappear of the view being cover always get call.
Note. viewWillAppear and viewDidAppear of the covered view controller always get called.
In the code that is experiencing the problem, I am pushing the new view controller in viewDidAppear of the previous ViewController.
Anyone know what I might be doing wrong or if the behavior I am seeing is expected?
The problem I am experiencing is that viewWillDisappear and viewDidDisappear of a ViewController does not always get call if another ViewController is pushed on top of it immediately upon application start up without user interaction.
Sound pretty sensible to me. After all, the "covered" view never appeared on screen, so it cannot disappear. I would expect this behavior.

Why is self.navigationItem.hidesBackButton not working?

I have a UIViewController that is pushed onto a UINavigationController and is currently displayed. When I go to start some asynchronous task inside the view controller, I can set hidesBackButton on self.navigationItem to YES, and the back button is hidden correctly.
As soon as the task is finished, and I set hidesBackButton back to NO (on the UI thread, I might add, I've made sure of this), nothing happens. The back button remains hidden.
Has anyone seen this before? What drives me especially crazy is that in my application (the same application), in a different UINavigationController hierarchy, the exact same code works correctly!
Are you calling hidesBackButton = NO from a thread? All UI operations should be done on the main thread, otherwise they won't have any effect.
i have not been able to replicate your problem on my machine. however, i faced a similar issue with tableviews even when i was updating my ui on the main thread. but calling setNeedsDisplay fixed that issue.
Can you try this and see if this works:
[self.navigationController.navigationBar setNeedsDisplay];
I guess this should work, you need to do the same, BUT ON THE NAVIGATIONBAR instead. please let me know if this worked - as i cannot test my solution because i never get this problem :-)
Have you tried forcing the view to refresh by calling setNeedsDisplay?
Maybe the OS is not picking up the changes instantly and you need to force it.
Have you tried using the setHidesBackButton:animated: method instead? Perhaps that has a slightly different behavior.
In my case I simply had to give a title to the view, as in:
self.navigationItem.title = #"Menu";
Marinus
I have had a similar issue recently. I tried literally everything I found in SO and other forums- nothing worked.
In my case there was a modally shown UINavigationController with a simple root controller which would push one of two view controllers (A and B) on top of the controller stack when the button A or B was pressed, respectively. Controller B was the one which was not supposed to show the back button. But still, sometimes it did, sometimes it didn't.
After hours of debugging, I managed to track it down. Controller A was a UITableViewController. Each time I selected a cell in this controller, the delegate would pop Controller A off the stack. BUT. I made use of a UISearchDisplayController as well. Turned out that popping the view while the search controller was still active messed up something in the navigation controller that made it impossible to hide the back button in Controller B afterwards (well, it eventually stayed hidden between viewDidLoad and viewDidAppear: but then it always turned visible).
So the solution (rather workaround) was adding this line to where Controller A was dismissed:
controllerA.searchDisplayController.active = NO;
// ...
// [self.navigationController popViewControllerAnimated:YES];
Hope this spares someone a couple of hours.

RetainCount for View Controllers in TabBarController -(aka releasing a tabBarController)

I have created an iPhone app where you start in a NavController and after a couple of levels you select an option from the table and an animated view pops in that has a tabbarcontroller at its root.
This is a completely seperate view that replaces the navcontroller. You tab around and when you want to go back to the options screen you press back and another animated transition plays swapping back the navigation controller removing the tab bar controller and releasing it.
The problem comes with releasing the UITabBarController. If you press the tab buttons to switch between tabs it seems you continually increase the reference count for the view controllers. Then when you call release on the tabBarController reference it will only release the view controller of the selected tab or any tabs you haven't viewed yet, and it takes one of the retain count on the others tabs viewcontrollers. This means you leak all your Model objects, custom cell objects etc from each of the other tabs that were not selected.
As an example of what I am seeing, if you create a new template TabBarController project in xcode and add a viewWillAppear method to the first view controller that prints out the retain count for itself. Start the app and press back and forth on the First and Second tab buttons and watch the log the retain count just keeps increasing.
So I am wondering if there is a way to release a tab bar controller and have it release all of its view controllers at the same time?
If this is true, it's a bug, and you should file a report on Apple Radar.
Just for completeness, I did post this problem in the apple dev forums looking for some confirmation but never heard anything back.
Checking out my app on OS3.0 shows that this behaviour is now fixed. Reference counts never go increase and releasing the UITabBarController appears to work.
Sadly I put a nasty hack in to fix this which doesn't play well with OS 3.0 so it's now conditional compilation time.