UIViewController pushed onto UIController embedded in UITabBarController not calling delegates - ios

I have a UITabBarController that has four UIViewControllers. These are set up in the app delegate and everything behaves as expected.
I have set the first UIViewController as the UITabBarControllerDelegate and that works fine too; as tabs are pressed shouldShowViewController fires as expected.
Inside the first UIViewController, the first tab, are buttons. One pushes another UIViewController using the standard:
[self.navigationController pushViewController:vc animated:YES];
This works just fine: the new UIViewController and it's view appear as expected.
However, when I press the tab button the shouldShowViewController function is called (as expected) and passes a reference to the first tab (as expected) but the child UIViewController is nowhere to be found. That is, viewController.navigationController.viewControllers is an empty array (count == 0).
To debug I implemented the UINavigationControllerDelegate and assigned the navigationController to the same class from the UIViewController and tab controller. It fires when called from the tab controller but not the view controller.
I've tried everything I can think of to find a reference to the topmost visible view controller but I'm stumped; it seems to vanish into a black hole. I"m ready to try to keep the stack manually but trying to keep a parallel array with system functionality built into it seems like a setup for a maintenance mess. I am using iOS6.

Related

UISplitViewController: Deinit DetailView in collapsed mode

I've been struggling on this for a while now, but I wasn't able to find a solution:
I've got an iOS 9 app that supports all device families, uses size classes and is programmed with Swift 2.0.
I'm using a UISplitViewController and everything works as I want, except in a collapsed environment (e.g. on an iPhone).
The Master-ViewController is a UITableViewController that triggers a replace segue when a cell is selected. In a collapsed environment this means, that the detailViewcontroller gets pushed onto the screen. The UISplitViewController visually behaves kind of like a UINavigationController.
However, when I dismiss the detailViewController with the back button or the swipe gesture it does not get deallocated until the a new replace segue is triggered in the Master-ViewController.
I assume that this is kind of a feature of UISplitViewController, since it was originally designed to show both contents next to each other. Nevertheless, in a collapsed environment I would like my UISplitViewController to behave like a simple UINavigationController, which deallocates the previously pushed detailviewController when popped.
I've been trying to manually change the splitViewController's viewControllers attribute after the detailViewController is popped:
if let firstVc = self.splitViewController?.viewControllers.first {
self.splitViewController?.viewControllers = [firstVc]
}
But that does not help. Simply replacing the detailViewController with an empty "Dummy"-ViewController doesn't work neither, since it automatically animates the transition.
Playing around with the UISplitViewControllerDelegate didn't help me neither...
Is there a solution for this (maybe simple? :)), that I'm too blind to see?

Switching between UIViewControllers in story board

As someone who usually used separate xibs in the past I thought I'd give storyboard a go as it seemed a lot simpler to use and much easier to develop with. I've been writing an application where the essential set up is this:
At the top of all this is a UINavigationController (first level). Then I have Multiple UIViewControllers (second level) with buttons in them which you can tap to switch between the second level UIViewControllers.
However a problem occurs when I start switching between the second level UIViewControllers. I first thought this was an initialisation problem with the NSMutableArrays because in my code I have a NSTimer set to loop periodically and found when I set a breakpoint during it, when I went forward to the next timer tick event there appeared to be different instances of the same NSMutableArrays and it seemed a gamble to try and insert new values into these array with it sometimes working, sometimes not (as it may or may not insert into the correct instance).
Then, looking at the memory usage under Debug Navigator I found the issue. Each time I "switched" between the UIViewControllers a new UIViewController was being initiated, along with all new variables.
The code I am using to switch between them is
-(void) perform {
[[[self sourceViewController] navigationController] pushViewController:[self destinationViewController] animated:NO];
}
Or essentially a push segue transition. This also explains why when I tried to switch back to my view, the data on that view was lost as it is a complete new view.
Does anyone know how to switch between multiple ones of these UIViewControllers (say 5) essentially like a UITabViewController would except without the tab bar being present?
First option you can do this: You can use a tabbarcontroller for switching viewcontroller and hidden the tabbar. Then on buttonclick setthe tabbar index.
Second option you can do this: Create one more view controller and in this viewcontroller subview the all switching viewController and when you want to switch viewcontroller just bring that viewcontroller view to front by delegate.
Do you need the navigation bar and other features provided by your top level navigation controller?
If not, you could use a UIPageViewController instead.
You set up all your second level view controllers and then just have to tell the page view controller which one to display.
If you implement the associated delegate methods, it will automatically provide swipe gestures to switch between them and nice animations to get them on and off screen.
You can also get it to put a UIPageControl at the bottom showing a dot for each VC with the dot for the current VC highlighted.

iOS Restoration - why is another View displayed before the one I'm restoring?

My storyboard has: NavigationController -> UIViewController 1 -> UIViewController 2 -> UIViewController 3 -> UITabBarController -> four UIViewControllers (a,b,c,d)
I'm adding restoration support to the app. I've added it to UIViewController #1 and #3 and am now adding it to UIViewController 'c' under the UITabBarController.
When I kill my app using Xcode when it's displaying UIViewController 'c' and then start the app again the viewcontroller's methods are called correctly and the content of its UITextFields are restored correctly.
But in placing breakpoints in 'c' view controller I can see that UIViewController 3 is temporarily displayed. It's viewDidLoad and viewWillAppear: methods are called.
What would typically be the cause of UIViewController #3 being displayed?
I've pressed on implementing restoration for my UIViewControllers and there doesn't appear to be any negative effect from an end-users point of view - without the breakpoints the display doesn't get a chance to update to show the intermediate view.
That's what view controller restoration is. The app launches from scratch; to reach the view controller that was being displayed at termination, the app walks the view controller creation sequence down the chain from the root view controller to the view controller that is to be displayed to the user. It couldn't possibly happen any other way. (After all, if VC2's Back button is to lead to VC1, then VC2 must be above VC1 in the nav controller stack.) And you wouldn't want it not to happen, because you might have important work to do as the sequence is reconstructed. By setting breakpoints in the middle of the restoration process, you have revealed "the man behind the curtain". But the user doesn't see that process (it is covered by the launch image), so there's no problem.
In particular it is very important that viewDidLoad is called in correct sequence right down the chain of creation, and that this happens for all view controllers before they are sent decodeRestorableStateWithCoder:, also in order down the chain.
(However, you should not count on anything having to do with viewWillAppear: and its cousins. These may or may not be called and you can't be sure just when. I regard this inconsistency / unpredictability with regard to the timing of viewWillAppear: as a bug, but Apple, unfortunately, does not.)

Change starting point for UINavigationController to detail UIViewController without loosing its context?

How can I change the starting point for a UINavigationController using a Storyboard without loosing its context?
I have a simple Storyboard with a UINavigationController including a UICollectionView as overview and a UIViewController as detail viewcontroller.
As long as I have the starting arrow pointing to the UINavigationController, it works fine. However I want to launch directly with latest detail UIViewController (on the right) opened skipping the UICollectionView. But when I drag the starting arrow to the detail controller I run into issues:
the actual detail ViewController content that is being populated in the prepareForSegue method in the UICollectionViewis then missing
the [self.navigationController popViewControllerAnimated:YES] in the detail view controller is not working as well. So it's not possible to go back to the overview UICollecionView
What's the best way to change the start up UIViewController without loosing its navigationControl context and preparefForSegue population method?
[self.mavigationController setViewControllers:#[…] animated:YES];
// just set any UIViewControllers array you want, you can replace or filter it. The last one in your array will be shown on the screen.

UIStoryboard popViewController

I'm using a UISegue in my application to automatically transition between viewcontrollers in my application. I'll call them A and B.
It worked as expected, however when I wanted to pop-back to the A from B, I attempted to call
[self.navigationController popViewController] however the B's navigationController property reports null.
As a second attempt I attempted to map a button, to a UISegue back to view controller A.
However this just creates a new ViewController.
As a work around, I ended up doing as a work around was to retrieve the B viewcontroller from the UIStoryboard and calling [A.navigationController pushViewController:B]
At which point, calling [B.navigationController popViewController] worked as expected.
This seems wrong, from a storyboard segue how can I return to the previous view controller?
I don't know about the class of your A and B controllers (whether UIViewController, UITableViewController or UINavigationController), but if you follow the following pattern, it should work.
In an empty storyboard, insert a UINavigationController. This will bring in two windows to the storyboard, linked with an arrow (a segue). The one on the right should be controller A.
In A, let's say, you add a button. The button will push B into the navigation stack.
Then, you add the second controller B, and drag from the button in controller A to controller B, and choose "push" from the popped menu.
If you only use a UIViewController (A) and push B, there is no navigationController to take care of popping.
Hope that help.

Resources