Relationship among window, rootviewcontroller, childviewcontroller, navigationcontroller in iOS - ios

I haven't really seen any resource that gives a good and simple explanations on relationship among window, rootviewcontroller, childviewcontroller, navigationcontroller and how they piece together in iOS development. Anyone one knows how to put this in a easy-to-understand way or any online resource or book that does a good job in explaining it?

Per the documentation on UIWindow:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIWindow_Class/
A UIWindow object provides the backdrop for your app’s user interface and provides important event-handling behaviors. Windows do not have any visual appearance of their own, but they are crucial to the presentation of your app’s views.
Xcode typically provides your application's main window, but you can add more if you need to.
From the documentation link you can see that UIWindow is actually a UIView
Enter your first view controller. Like providing a main window, when you start a new Project in Xcode the project template usually wires up your initial view controller, which as the name implies controls a view (UIView).
You could call this initial view controller your RootViewController but if you get a handle on the UIWindow you could just as easily swap out the current initial view controller's view for any other view controller view you like.
That probably doesn't help with hard and fast rules for things, but if I understand what you are asking, RootViewController is likely the initial view controller for you application. For example, if you are using Storyboards, Xcode typically makes Main.storyboard, you will see a gray arrow pointing to the UIViewController representation.
This is pointing to the Storyboards Initial View Controller. You can verify this from the Attributes Inspector. Select the view controller then select the attribute inspector:
So that's basically RootViewController. ChildViewController is just any other view controller that is a child of a view controller.
I assume what you are referring to is:
addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:
You can read more about these methods here:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/
Under Implementing a Container View Controller
The quick gist of it is, A View Controller controls a view. View's can have subviews. Those subviews can come from other View Controllers. The methods outlined above pretty much just enable things like viewWillAppear, or viewWillDiappear to be called on the child view controller automatically when those methods are invoked on the parent view controller.
Per the docs:
By default, rotation and appearance callbacks are automatically forwarded to children. You may optionally override the shouldAutomaticallyForwardRotationMethods and shouldAutomaticallyForwardAppearanceMethods methods to take control of this behavior yourself.
a NavigationController is just like any other View Controller. It contains some special behavior for transitioning between views, but like other View Controllers it has a View (UIView) that it manages. A navigation controller could be your Initial View Controller / RootViewController just as any other View Controller can be, it all just depends on what you are trying to do. For example, a simple app that is just a list view, where you can tap an item and get a detail view could be constructed as:
1) Initial View Controller -> NavigationController
2) The NavigationController's first ViewController (Apple calls this a RootViewController) would then be a TableViewController.
3) Selecting a TableCell in the TableView (TableViewController manages a TableView) would then transition you to your Detail View Controller. The Navigation Controller knows how to do all that Sliding back and forth drama.
That's a pretty simplistic overview you can search the internet/youtube for more full featured tutorials outlining the same thing in more detail.
Example: https://www.raywenderlich.com/113388/storyboards-tutorial-in-ios-9-part-1
It's worth your time to do a few of these to get your bearings. Yes, it will likely cost you a few hours of your day. Take heart, everyone who ever started doing iOS development had to go though the same thing. =)

Related

IOS: One navigation view controller with many different views - how should I do it?

I'm trying to create an IOS app that has one navigation view controller with several bar buttons, where each button changes the content of the view itself. Most of my views are custom views anyway, so I won't really see any clear previews in the storyboard anyway.
I'm thinking about creating one navigation view controller, and several NIB files to represent each view. Each NIB will have its own class with all the IBOutlets and IBActions.
Then, when a button is clicked in the navigation view controller, just switch to a new view by clearing the old one (removeFromSuperview), and call loadNibNamed to load a new view.
Does this sound reasonable or will all this deserializing be expensive in terms of CPU? Would it be better to just create different viewcontrollers in the storyboard, with segues etc, and copy those nav bar buttons to each view controller?
The simplest solution:
ViewController->
View->
rootViewOne
rootViewTwo
rootViewThree
...
upon your bar button's action,set specific rootView's hidden property to true or false:
self.rootViewOne.hidden = currentIndex == 0
self.rootViewTwo.hidden = currentIndex == 1
self.rootViewThree.hidden = currentIndex == 2
You can add your other view controller/s as child view controller.
In this way, you will have code for different views in their respective view controllers and your main/parent view controller will not be messy.
To add child view controller:
// Get instance of your view controller
UIViewController *childViewController = [UIViewController new];
// Add your view controller as a child view controller
[self addChildViewController:self.loginView];
// Set frame for your childViewController's view
[childViewController.view setFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height)];
// Add childViewController's view as a subview to your viewcontroller's view
[self.view addSubview:childViewController.view];
// Notify your main/parent controller that a child view controller is being added
[childViewController didMoveToParentViewController:self];
To remove child view controller:
// Notify the childViewController that it will be removed
[childViewController willMoveToParentViewController:nil];
// Remove childViewController's view
[childViewController.view removeFromSuperview];
// Remove childViewController from your main/parent view controller
[childViewController removeFromParentViewController];
Hope this helps.
UPDATE - Embedded swapping by Sandmoose Software:
http://sandmoose.com/post/35714028270/storyboards-with-custom-container-view-controllers
Here's a snippet from the "how-it-works" section:
The segue between ViewController and ContainerViewController is an
embed segue. The segues between ContainerViewController and its two
child view controllers is a custom segue. This custom segue is named
Empty and is a subclass of UIStoryboardSegue. It contains an empty
perform method. The ContainerViewController will take care of moving
the child view controllers into and out of place. However, the fake
segues are needed to create the connections in the storyboard.
If you’re like me you cringe at the thought of having a fake/empty
class like this but the benefit is that it allows us to stay firmly in
the world of storyboard idioms without resorting to programmatically
loading isolated storyboard scenes. It’s one tiny bit of ugliness
which allows us to preserve the usefulness and elegance of
storyboards. The storyboard still visually represents the scenes and
their relationships accurately. We can still use segues to control
what happens.
---------- Old answer below (phfffft!) ------
You pose several different questions here: one regarding custom buttons in the nav bar of a nav controller, another about assigning multiple views to the nav controller, and one about placing the view in separate XIB files, while maintaining IBOutlet connections and such.
The first one calls for a tab bar controller, which you can customize to look in whatever way you deem fit, even like a nav bar (ADC has ready-to-use sample code, "UIKit Catalog (iOS): Creating and Customizing UIKit Controls", which fits your needs).
The second can be done easily in Interface Builder by following any number of instructions freely available on YouTube, at Apple, and elsewhere on the Internet; you'll find it an extremely intuitive process. If you can drag-connect a tab bar controller to a view controller, you can intuit the rest. Otherwise, Apple has sample code for customizing the navigation or transition between views in a single view controller interface. "State Restoration of Child View Controllers" provides the best structure for what you want (just pull out the restoration-related code, and use the rest).
The third is not intuitive at all; and, as far as I know, there are only a couple of sets of instructions that exist for separating views (or other view controllers and their views) from a parent or top-level view controller. Here's one I haven't tried yet, so I'll be interested to hear how it worked for you:
http://digginginswift.com/2015/08/30/making-reusable-views-in-separate-xibs
The technique I use involves creating a storyboard with a single view controller to start, followed by a new view controller embedded in a container view for each of your intended views; then, deleting the view in each of the child view controllers, which leaves place for the views you set up in separate XIBs. They are connected by setting the File's Owner to the parent view controller. I can send you sample code, if you'd like to try a different approach than the aforementioned website offers.

What are the benefits of using a UINavigationController over adding a view with addSubView?

Let's say I have two pages with two UIViewControllers, UIViewController1 & UIViewController2.
If I want to show a UIViewController2 on top of UIViewController1 I have three options:
using UINavigationController pushViewController.
using presentViewController.
addSubView : UIViewController1.view.addSubView(UIViewController2.view)
If I need to a transition between my views, I prefer the third option because it gives me much more control over the views.
Is there any difference between these three options in terms of performance?
Before iOS 6 you were not supposed to do option 3. View controllers were meant to control the entire screen. In iOS 6 Apple added support for parent and child view controllers. You could make another view controller your child and add it's content views to yours.
If you are going to use option 3 then that's what you need to do. If you don't you will have a variety of problems.
There is even support for parent/child view controller built into storyboards. You can add a container view to a view controller, and then control drag from the container view onto another view controller's scene. When you do that the system creates an "embed segue" that sets up the child view controller inside the container view and wires up the parent/child relationship for you.
Your first 2 options are for when you want the new view controller to replace, or at least cover, the first view controller. Option 3 is for when you want a region of your screen to be managed by another view controller.
Option 3 (using a child view controller) does mean that both view controllers will be active and in memory at the same time, so you can't release the covered view controller's data storage while it's inactive like you can in a push or modal presentation. However unless your view controllers hold and present huge data structures this isn't much of a concern. In both a push and a modal presentation the covered view controller sticks around in memory anyway, waiting to be uncovered. You have to take special steps in order to free any memory while a view controller's view is covered and then reallocate it when it is displayed again - something that is unusual.
Just for two view controllers, it will not create major difference. UINavigationController is mainly used to maintain navigation stack.
But as you are having just two view controllers, you can use alternate way also.
If you are looking for transitions with NavigationController, you can use UIView Transitions for customisation of push pop animation.
Please refer following links for UIView Transitions
https://www.objc.io/issues/12-animations/custom-container-view-controller-transitions/
http://www.raywenderlich.com/86521/how-to-make-a-view-controller-transition-animation-like-in-the-ping-app
https://www.captechconsulting.com/blogs/ios-7-tutorial-series-custom-navigation-transitions--more
http://applidium.github.io/ADTransitionController/

Please clear some confusions regarding UIViewController

Please clear some confusions regarding UIViewController
I found this article Abusing UIViewController and here are the links link1 & link2
and summarised points
This is author's (and Apple’s) advice In a nutshell:
One (and only one) view controller should be responsible for a whole hierarchy (or screenful) of UIViews.
Mostly, you should only use one view controller per screen. Essentially the rootViewController of the current UIWindow should be the only UIViewController with a visible view.
Each different screen should have a different view controller i.e. one controller should not control more than one screen.
You should NOT nest custom UIViewControllers within a view hierarchy.
If more than one UIViewController hangs off the application’s UIWindow, only one of these will get the messages for changes in orientation. The other(s) will NOT get these messages.
Nested UIViewControllers are not guaranteed, or likely, to receive messages for changes in orientation or lifecycle messages such as viewDidAppear:, viewWillAppear:, viewDidDisappear: and viewWillDisappear: even though they inherit from UIViewController. Only the topmost UIViewController is certain to get these messages.
Please clear point number 2 and 3
because when we use UINavigationController or UITabBarController we use multiple subclasses of UIViewController. And ios device has only one screen.....
This article Abusing UIViewController highlight apple suggestion
Note: If you want to divide a view hierarchy into multiple subareas
and manage each one separately, use generic controller objects (custom
objects descending from NSObject) instead of view controller objects
to manage each subarea. Then use a single view controller object to
manage the generic controller objects.
and in apple docs under heading of Coordinating Efforts Between View Controllers apple saying
Few iOS apps show only a single screenful of content. Instead, they
show some content when first launched and then show and hide other
content in response to user actions. These transitions provide a
single unified user interface that display a lot of content, just not
all at once.....
My requirement is NOT to use any container or modal or popover, I want to do manual management, I have two view controllers VC1 & VC2. VC1 is the root view controller now I want to switch/transit/move to VC2 what should I do?
VC1 should be the only subclass of UIViewController and VC2 should be the subclass of NSObject to manage a particular view in VC1 hierarchy?(the show hide thing by apple doc).
VC2 can also be the subclass of UIViewController, I just remove VC1 from root view and add VC2 as root view?
or what is the correct way?
Container view controllers (like UINavigationController) allow working around the one-VC-per-screen rule. Since iOS 5, developers have been able and allowed to write our own container controllers (which aren't actually much different from normal VCs). Generally this means that writing non-VC controller objects is less necessary than it used to be.
In your situation, where you want to replace the root view controller, your option 2 makes more sense. Use VCs where you can, and non-VC controller objects only when you can't. Since you're replacing the whole screen's content, just switching the UIWindow rootViewController makes the most sense (edit: alternately, many devs would just use a navigation controller to present the second view, because it's simple and convenient).

Segue always loads new instance of view

I'm executing a segue like so;
[self performSegueWithIdentifier:#"showSecondView" sender:self];
But the behavior is that it will always "load" the new view rather than show the existing view if it was already loaded.
My question is, how can I keep a view in memory once I've loaded it, so that future segue calls will simply "show" the existing view?
Thanks
EDIT:
Here is my user interface design. It's essentially a custom side tabbar view controller with a UIView (the big gray block) where all of the subviews are placed.
The short answer is that iOS isn't well suited for that, but you might be able to do so. It depends.
The question is how is that view's controller represented in the view controller hierarchy. The standard options are pushViewController (a push segue) or presentViewController (a modal segue). You might be able to do a custom segue that takes advantage of view controller containment (see WWDC 2011 session 102), but I'd be surprised if that would be something you'd want to pursue. Usually when you hear people talking about the frustration of creating new views is a result of their wanting to return to some main view, but neglecting to popToRootViewController and instead having a segue back to that root scene.
A wholly theoretical (and probably impractical) answer that might come up is to use a singleton and do some slight of hand to transition views, but after watching WWDC 2011 session 102 on view controller containment in which they belabor the importance of keeping one's view hierarchy synchronized with the view controller hierarchy, so I don't think that makes sense.
I might be able to make a more meaningful suggestion if I understood your desired user interface. For 99% of apps, they are geared around pushing/popping views, presenting/dismissing modal views, or using some container (e.g. a tab bar container or some custom container) for jumping between sibling views. What is your user interface flow?

iOS container view controller - Why does transitionFromViewController need the fromViewController?

When using custom container view controller, I don't quite understand why the presenting view controller needs to specify the from, because being the container class, it should already know what's in the view hierarchy, no?
transitionFromViewController:toViewController:duration:options:animations:completion:
Container view controllers sometimes need to put the views of the contained controllers into specific subviews of their own view. (For example, a SplitViewController reimplementation might have left and right positioning views holding the master and detail controller views respectively.) Providing the fromViewController tells UIViewController where in the view hierarchy the new controller's view should be inserted, and also which specific view should be removed after the animation.
(contrary to another answer, the frames of the views aren't set for you at all. You do that, before the call, and in the animation block. The "Creating Custom Container View Controllers" system guide in the docs has a pretty good example.)
As it happens, actually using transitionFromViewController:... appears to be optional. You can manage your view hierarchy manually, with or without animations, and it works fine. I'm still forming my opinions, but I think I prefer to do it manually, to more easily handle cases where one of the VCs is nil.
This is done this way to allow you to have a view controller that has views with viewControllers in it. The from defines the originating view controller and gives the system the ability to position the animations appropriately.
Imaging you had a view with 4 views in it like tiles. the main view controller can consecutively call this on its "child" view controllers and with the from -> to specification, it won't make the assumption that the caller is the from viewController.

Resources