After upgrading xcode and compiling my app using iOS 6 SDK I got many crashes among the app. From what I was able to track down it looks like UIKit messages deallocated view controller during modal segue instead of the newly created one. Here's how it looks:
I have a Tabbar Controller which displays a Navigation Controller. Another view controller that is being presented by the Navigation Controller displays a Modal View Controller.
TabbarController --> NavigationController --> ViewController (presenting) --
| shows using modal segue |
--> ViewController (presented)
Steps to cause the crash:
Access the View Controller (presenting) in hierarchy shown above. It is not root view cntrl but higher.
Trigger the segue to the modal view controller.
Pick a tab from the tab bar (whichever) and go back to the same View Controller (presenting). Picking a tab calls popToRoot on the Navigation Controller.
Again trigger the modal segue to the View Controller (presented)
Crash: Zombie object - View Controller (presented) - got messaged
Why?
It looks like on previous iOS when popToRoot was called and View Controller (presenting) was being cleaned up also the modal view was destroyed. So when it was accessed again it was recreated and presented.
On iOS 6 from what Allocations Instrumentation shows the modal view is destroyed together with
View Controller (presenting). But when it's being accessed for some reason UIKit creates a new modav view controller but then messages the old one that is not existent anymore. Doesn't make sense.
One other thing that makes me wonder is that on iOS 5 Allocations Instrumentation tool never shows me the View Controller (presented) with retain count = 0 but iOS 6 does (afterwards it makes it -1).
I know this is probably very difficult question to help me with but maybe someone was already tackling problems with iOS 6 and such segues?
From Allocations Instrumentation tool I can tell that many things got changed in the implementation of segues on iOS 6.
I've end up implementing custom segues for presenting those modal views. Seems like a quite good idea here.
Maybe one is not supposed to display a modal view inside tab bar view?
Related
I have an app that must support iOS 7-9. The views are laid out in storyboard, it's a tab bar controller, with each tab containing a split view controller.
Everything works fine, except with an iPhone running iOS 7. I have the following code to collapse the split view controller to show the detail:
UINavigationController *splitNav = self.navigationController;
UISplitViewController *split = splitNav.splitViewController;
split.delegate = self;
But on the iOS 7 iPhone, split is nil (as there is no split view controller under iPhone on iOS 7) so splitViewController: shouldHideViewController: inOrientation: never gets called and I'm stuck in a weird state.
I tried push the detail controller onto the navigation controller manually, but the view never loads (just get a black screen), although the controller logic executes.
Can I either set that behavior with with storyboard instead of in code or is there some other way to reference the detail of a split view controller that doesn't exist?
Im trying to present a modal view controller from subclass of UITabBarController. I present it from viewDidLayoutSubviews method. Everything works fine on iOS 7 but in iOS 8 when app stars i still breafly see TabBarControllers first tab.
TabBarController is set as initial view controller in storyboard.
Is this even a good way to present it or there is something for iOS 8 that i dont know?
I don't have the rep to post a comment, so I'll seek clarification and provide guidance through this answer.
Is the intention that the modally presented view controller will be the first thing people see when they launch the app? And then I suppose it gets dismissed, and behind it will be the tabbar controller? How is your storyboard currently set up for the modal view controller if the tabbar is set to be the initial view controller?
One place to start could be to move to code to viewWillLoad or viewDidLoad rather than viewDidLayoutSubviews. I could also suggest to just make the modal VC the initial view controller
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.
I have been developing an iPhone application using the Detail View template. At some point I realized that I wanted my application to have a Tab Bar View controller as the root view controller. It seems that you do not want to push a tab bar view controller onto a navigation view controller. So I decided to start a new tab bar project and migrate my existing application code over. I thought this would be easiest.
So I have done that and the project builds without a problem. But I cannot seem to reassign the tab bar view controllers to ones which I already have. So I am replacing, "FirstViewController" with one of my custom ones. When I attempt to run the application it calls:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
And bombs with a SIGABRT error. I'm not sure why this is. I cannot see what the default view controller (firstviewcontroller) is implementing that my custom view controller is not.
Can anyone give me some ideas of what I should check?
Thanks!
update
It seems that my problem is related to the fact that my custom viewcontroller is of type UITableViewController. If I change this to be of type UIViewController it seems to work.
Update
I added a Navigation controller to the storyboard and created a relationship from it to a blank TableViewController. Then I assigned this TableViewController to my custom UITableViewController class. This seems to work. I'm not sure what plumbing was missing before.
The UIViewController docs mentions about -viewWillDisappear:
"This method is called in response to a view being removed from its
window or covered by another view. This method is called before
the view is actually removed or covered and before any animations are
configured."
In iOS 4.3 and lower we are supposed to present a viewController and not add a viewController's view to the view hierarchy explicitly, so the calls -viewWillDisappear or -viewDidDisappear would be triggered when a new view controller is being presented over the existing view, in which case 'covered by another view' is true! But what if a viewController's view is hidden since another view obstructs the viewController's view? Do we get these callbacks?
Well, in iOS 5 there is a UIViewController containment concept where views can be directly added as subviews in view hierarchy by setting the parent-child relationship between viewControllers. So, unlike <= 4.3 OS, -viewWillDisappear and -viewDidDisappear calls should ideally be triggered when a viewController's view is obstructed or covered by some other view, which I have verified by a sample project that it is not happening in SDK 5.0.
Has anyone found this problem related to these callbacks?
Or, is my understanding correct?
Thanks,
Raj
Someone has the same kind of problem here :
iOS 5 : -viewWillAppear is not called after dismissing the modal in iPad
You should read the answers, I found them very interesting.