Is it wise to "nest" UIViewControllers inside other UIViewControllers like you would UIViews? - cocoa-touch

I've got a fairly complex view, for me anyway, that has a few "trays" with custom interface items on them. They slide in and out of my root view. I'd like to nest (addSubview) the items inside the view. Each needs some setup before being displayed...and none can be configured in IB (they're subclasses of UIView).
I'm wondering if it makes sense to subclass UIViewController for each "tray" and then have the VC's view property point to the "tray" view which I can populate with my custom UIView objects. This way I can leverage the viewDidLoad, etc... methods in UIViewController.
I'm not aware of others doing this - at least in the few samples I've looked at. It would create a situation where there would be multiple view controllers being displayed on the screen at once. from the Navigation controller itself on down to the rootViewController and its view and then any number (well, screen size permitting) of these small trayViewControllers. If so, how's the responder chain work? i assume it'd go from lowest UIView to its enclosing VC, then to that VC's parent view, then that view's VC, etc. etc. repeat, repeat.. up to UIApplication... am I asking for trouble?
OR, do I just stick with UIViews and adding subviews into subviews, etc. etc..

Prior to iOS 5.0 this will specifically not recommended because the nested view controllers' lifecycle events – viewWillAppear, etc. – won't be called. See Abusing UIViewControllers.
With multiple UIViewController’s views visible at once some of those controllers may not receive important messages like -viewWillAppear: or -didReceiveMemoryWarning. Additionally some of their properties like parentViewController and interfaceOrientation may not be set or updated as expected.
iOS 5.0 added containment UIViewControllers that correctly handles those lifecycle events by adding child view controllers.
- (void)addChildViewController:(UIViewController *)childController
I spent countless hours trying to get nested view controllers to work in iOS 4. I eventually did, but it required a lot of glue code that was easy to get wrong. Then I saw the warning in the docs.

I'm trying to do the same thing, but was dissuaded from your approach by Apple's documentation, which states that "You should not use view controllers to manage views that fill only a part of their window—that is, only part of the area defined by the application content rectangle. If you want to have an interface composed of several smaller views, embed them all in a single root view and manage that view with your view controller."

My experience on what you are trying to do has been a good one. I try to keep nib files as simple as possible, so I take any posible "subview" and encapsulate it in its own nib file with it's own view controller, therefore I end up having nested view controllers.
In one of my apps I have a very complex table view cell, that has a subview. So I ended up having a hierarchy that goes like this: the tableview controller on the top level, the tableviewcell's controllers for each row and inside each of these a subviewcontroller for the subview inside each cell.
And everything works fine.
Pardon my english.

Related

Issues that can arise when using UIViews instead of UIViewControllers?

I've been trying to figure out what can go wrong when using UIViews instead of UIViewControllers and haven't been able to find any therefore I've been just using custom UIViews when generally UIViewController is recommended for some reason.
I prefer UIViews mainly because when custom animating for transitions they're easier to manipulate as far as I know. Correct me if I'm wrong.
Also, I customize everything on my own programmatically such as tab bar, navigation bar etc hence to me, a custom UIView does everything a UIViewController does..
So, is using a separate custom UIView instead of a new UIViewController problematic? If so, please enlighten me..!
Edit
I am aware of MVC model and by UIViews instead of UIViewControllers I mean ignoring the whole one UIViewController per screen thing and use UIView as a container for all objects for certain screens.
For example, when showing menu screen, instead of pulling a UIViewController up for its own "section", I just don't do UIViewController at all and do it with a custom UIView which works as a container, draw/add everything in there. The same goes for the rest of "sections".(settings, option etc etc)
Is this problematic?
I've been trying to figure out what can go wrong when using UIViews instead of UIViewControllers
You cannot do it generally, because view objects and view controller objects occupy different places in the Model-View-Controller hierarchy. They are not even one-to-one with each other, because a single controller often manages multiple views.
I prefer UIViews mainly because when custom animating for transitions they're easier to manipulate as far as I know.
In situations when a piece of functionality can reasonably go in either a view or in a view controller, it most likely belongs in the view, not in the view controller, so your observation is correct. Custom animation that can be encapsulated in a single UIView should be encapsulated in the UIView, even though the same code could go in a UIViewController as well.

Custom segue that 'finishes' early?

I'm looking to implement a custom segue that pushes to a UIViewController, but completes before the new UIViewController fully fills the screen, leaving some of the source view controller still in view and functional. (For example; new view controller covers half of the user interface).
I'm keen to use a segue rather than a view that is moved using CGRect, Quartz framework method, or similar, as constraints get messy really easily, unless a custom segue could utilise such methods(?)
Any pointers greatly welcomed! :)
For this task you would use a container view controller, which manages and displays the content of multiple other view controllers at a time while letting them interact with their views like normal. An example of this would be the UISplitViewController, which displays two view controllers' views at a time, one on each side of the screen. You can design segues that swap out one view controller of the multiple on display in a container view controller, similarly to the Replace Segue implemented by Apple to swap out a UISplitViewController's detail view controller (the one on the right hand side).

Subview vs childViewController

This is a general question but I'll ask it using a specific example to avoid confusion:
I'm developing an app that has a UIPickerView among other things on a single screen. I was wondering if it's appropriate the make a custom PickerViewController class to control my UIPickerView and then add my PickerViewController as a childVC...
OR should I just create an instance of UIPickerView in my existing VC and control it from there?
When should I do either of these options and what are the advantages of them?
Appreciate the help amigos.
If the UIPickerView is simoultaneously on the screen along with other UI elements, then you should just add it as a subview. The concept of a view controller is for when you start managing a completely different UI/window/set of elements (however you call it). If the picker view closely belongs to the functionality of the other elements, you should not create a separate view controller for it.
iOS 5.0 introduced the notion of child view controllers. Originally, any view controller except for UINavigationController and UITabBarController had to be modal and full screen. In iOS 5.0, you can now have several UIViewControllers present on one screen. This means that one UIViewController can have many children (UIViewController), where each child is responsible for controlling more specific views and models.

MVC and UIButtons

I have an iPad project I'm working on that dynamically creates a number of buttons that I need to add to the main view of my application. I was planning on firing a method that lives inside my View from my ViewController...say it's called add_buttons. It's my impression that in the MVC pattern, the view should handle the rendering of buttons and the general display, but the controller should handle the interaction. I'm also under the impression that it's bad design for the view to "know" about the view controller.
So I guess my question is, should I have my button tap logic contained in my controller? If so, how do I handle the separation? If I'm creating the buttons in my view, then it would have to have a reference to the view controller to use as the delegate for the event handler. If I create them in the controller, then I feel like I need to set certain UI elements in the controller which seems wrong to me. I know I'm missing something obvious but searching so far has proven fruitless.
Can anyone point me in the right direction?
The button tap logic most certainly belongs in the controller.
The code that creates the buttons probably belongs in the controller too. However, it would make sense to include a view method that returns a button with its appearance configured but not its behaviour.
Some general pointe:
View controllers and their view are very tightly coupled.
If in doubt it's best to put the code in the view controller.
A views interface should deal with primitive data types (e.g. strings, numbers, images). Views should not need to know the specifics of model objects.
Also, the naming convention for methods lowerCamelCase. Eg:add_button should be addButton.
when you add button to view,
[myButton addTarget:nil action:#selector(myButtonPressed) forControlEvents:UIControlEventTouchUpInside];
in view controller add
-(void)myButtonPressed {
}
with target:nil event will be handled by first controller containing this view
I rescently finished a project where I had to dynamically create UIViews which contained both UITextfields and UILabels.My approach to this problem was to call the "addViews" function from within the view controller. I figured this to be a better and easier approach rather than dealing with view controllers from inside the UIView. I have tested my approach and works completely fine (dynamically change UIView size and adding other UIViews with a UITextfield and a UILabel).

Putting an ADBannerView on top of a UINavigationController

I'm trying to put an iAd banner in an app that is based on a UINavigationController (it's not the standard nav-base app proposed by xcode, cause I don't need the table view).
I'd like to place an ADBanner on its bottom, to be always visible, no matter how the user pops and pushes views.
I studied the iAdSuite example in the apple sample code, but, though it's reported among the "best practices", I don't think it's the best practice for what I need. It basically declares an ADBannerView in the app delegate class and then implements the ADBannerViewDelegate methods for every single view the app needs. That means implementing the ADBannerViewDelegate methods over and over again on every view controller class you need! It doesn't seem too smart... :(
I'd rather prefer to have an approach more similar to what Apple itself does in the tab bar based app, where you have a part of the window always occupied by the tab controller and all the views switching above without affecting the tab bar view below.
You can't directly put an ADBannerView along with the nav controller in the app delegate, because ADBanner needs to be placed in a view controller (you get a runtime error otherwise).
I tried to subclass from UIViewController, implementing the ADBannerViewDelegate in this class, and place it in the rootViewController along with a UINavigationController but I'm not having good luck with this approach...
Has anybody found a good, simple way to to this? Any hint?
Thank you for any help...
You can have just one class for ADBannerViewDelegate, and just one instance of ADBanner itself. When the currently active view changes, remove ADBanner from the old view, add it as a subview to the new view.
EDIT:
to clarify, you don't need each view implement the ADBannerViewDelegate. You only should have one class implement it (that class doesn't have to be a view controller for that matter).
You would also need to maintain a somewhere a property that would point to the currently active view (e.g. you can update that property in your Navigation Controller's navigationController:didShowViewController:animated:, or come up with your own protocol for that if your views appear in a more complex way).
Then in your ADBannerViewDelegate you'd just resize the view currently pointed to by that current view property. The actual view doesn't even have to know it has an ad in it ;)