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).
Related
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. =)
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/
I am trying to create a class that is similar in functionality to the UITabBarController, but with some fundamentally different functionality. It is called a dropdownViewController and has a primary content view with a UITabBar-like interface at the top of the screen that allows for other UIViewControllers to be modally presented and dismissed over this primary viewController.
I would like this class to be able to be set up using the storyboard to some extent, and I have created a custom Segue that connects my dropDownViewController class with each of its child viewControllers.
My current solution is to assign identifiers to each of the Segues that are then stored in array within the dropdownViewController. I can call the segues programmatically using the performSegueWithIdentifer: method, but this solution isn't as flexible or intuitive as I would like to to be.
Right now, all the custom Segues that I have setup are connected to the "manual" triggered segue in the storyboard connections panel for the dropdownViewController. (I would put screenshots but this is my first post)
However, I want to mimic the functionality of the UITabBarController class, which has an alternate triggered segue in the storyboard connections panel called viewControllers that each of its child views are assigned to. Unless there are some compile-time macros handling these story board interactions, I assume that the UITabBarController uses these connections to determine what it's view controllers are. However, I can't figure out how to setup this functionality with my own class
After searching around for a solution, it seems likely that this is functionality Apple kept for its own use and is limited to their own classes as a feature in Xcode, but if anyone has solutions or ideas it would be greatly appreciated.
I haven't tried this, but I think you should be able to do it with your own custom segues. In the perform method, you would just add the destination view controller to the source view controller's (DropDownViewController) array of view controllers. In the DropDownViewController's viewDidLoad method (or maybe in an initializer or awakeFromNib, not sure which is most appropriate), you would execute all these segues so that they run right after the controller is loaded like is done for a tab bar controller.
Referring to this question: addChildViewController alternative for iOS 4.3
My app requires support for 4.3 so I am unable to take the approach mentioned in the Apple guidelines for container programming - http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html
Directly swapping the views of each ViewController works for me currently, however, when it comes to pushing a new View Controller, these 'children' do not have a reference to the container's self.navigationController so they are unable to push a new controller on the stack.
What is the best practice for being able to access the UINavigationController of the container class in iOS 4.3. It is a shame I am being forced to support 4.3 as the childViewController pattern outlined in the Apple documentation is exactly what I'd need otherwise!
Thanks,
Tim.
In iOS 4 and before, you are not supposed to create your own UIViewController hierarchy, so you have to manipulate views directly as subviews of a UIViewController's view.
However, if you do this correctly, there is still a UIViewController hierarchy and it does still work. There is no circumstance in which you "do not have a reference" to the UINavigationController. A view has a superview, which is another view. A UIViewController's view has a reference to the UIViewController (as its nextResponder). The UIViewController has a reference to its parent UINavigationController if there is one.
If that's not the case, you're doing something very wrong with view controllers.
Apple's documentation says this (for iOS 4 and before), and you should take it very seriously:
You should not use multiple custom view controllers to manage different portions of the same view hierarchy. ... 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.
The rule in iOS 4 and later remains the same: do not use a UIViewController except as part of a legitimate UIViewController hierarchy, where the view controller's view is in exactly the same hierarchy, as in this diagram from my book:
Observe that the view controllers are parent and child and that their views are superview and subview. That is how to use a view controller hierarchy. If you're doing things in iOS 4 that would violate this, don't. Use views but not view controllers.
I'm creating an interactive touch book in iOS. I'd like to know what the best controller is to use for books. (e.g. UIViewController, NavigationController, etc.). I'd prefer to stay with storyboard options.
And secondly what is the best way to handle pages? A separate ViewController for each page? a separate view for each page?
UIPageViewController
From the docs:
Page view controllers allow users to navigate between view controllers
using the specified transition. Navigation can be controlled by the
user using gestures as well as programatically.
View controllers are either provided one at a time (or two at a time,
depending upon the spine position and double-sided state) via the
setViewControllers:direction:animated:completion: method, or provided
as-needed by the data source. Gesture-based navigation is enabled only
when a data source is provided.
To alter the behavior of this class, you should provide a data source
and delegate. This class is not intended to be subclassed.
As for your second question, yes it is easiest to manage each page as a view controller since UIPageViewController is a container view controller and it holds an array of view controllers.