iPhone. View architecture - iphone

Can anyone summarize the relationship between the following items?
Content View
View Controller
Nib
the view, subclass of UIView
Application delegate
I got very confused about these. Coz some people say the "content view" contains the "nib" while other people say "content view" and "nib" are not containing each other.
Many thanks!

Oh man… that's not so easy. But I'll try.
Application is being launched from main().
Application delegate receives callbacks from Application during runloop. For example, when app finished launching or something else.
Usually application contains single instance of UIWindow, that is the root of all view hierarchy.
UIWindow can have UIViews, they can have UIViews by themselves. So, there's a hierarchy of UIViews (a tree)
Each view has controller, that gets user input and other events and controls UIView (for example, tells it to redraw itself because of user tap). Controller can be standard or custom, written by developer.
Content View is a normal view. Usually within a table cell. UITableViewCell instance has a property that is called contentView. It's a normal view and it can be any UIView subclass.
NIB is another story. You can create whole view hierarchy by yourself. But there is an alternative way: use Interface Builder. After creating views/subviews in the interface builder — you can save this hierarchy with all its properties as a single (serialized) file. And load it at once during application run.
NIB has three main objects. File Owner is an object, that you'll get when you send some message like
+ (BOOL)loadNibNamed:(NSString *)aNibName owner:(id)owner
Here owner will be filled with all properties of File Owner from the NIB.
First responder - first receives input. You can simply forget about it for now.
View — is the main view. Usually it is linked to a view property of File Owner.
It's a veeery short overview of all these things. You really have to read documentation to understand it better.

Related

Loading a custom UIView from a XIB file within a XIB for a ViewController view

I have an WizardSequenceViewController with an IBOutlet WizardView *_wizardView. In many WizardSequenceViewController.xib file I have the view outlet connected to the File's Owner - WizardSequenceViewController. I have a subview of that view defined with the class attribute set to WizardView. I have connected that WizardView to the outlet in the File's Owner. Finally, in my WizardView.xib I have a UILabel that I have placed in the file to test if the view is being rendered. When I select the WizardSequenceViewController from my tab bar, I see the superview view but not the subview _wizardView. When I set a breakpoint in my -(id)initWithCoder method in my WizardView.m file I see it stop there, so I know that it is calling that initializer (and thus it should be using the xib to load that file). I have tried many iterations and variations to get this thing to work but I can't and I am going crazy. Does anybody have any ideas?
From Apple doc "View Controller Basics, About Custom View Controllers":
The one-to-one correspondence between a view controller and the views in its view hierarchy is the key design consideration. You should not use multiple custom view controllers to manage different portions of the same view hierarchy. Similarly, you should not use a single custom view controller object to manage multiple screens worth of content.
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.
Maybe you can't do a view-and-subview outlet setup in a view controller. And I'm not sure assigning the subview outlet to a separate NSObject subclass would work either, because how would you present it? Could you write your subview programmatically, using initWithFrame and addSubview, instead of making it an outlet? Or, if you really want to set it up graphically, could you assign it to a separate view controller as owner? Then the top view controller will call presentModal on the sub view controller. Or, if all you need is a UILabel as a subview, just add the label to the main view?
Even I faced a similar issue. But got it resolved by following steps given in the following link. Hope it helps.
http://blog.yangmeyer.de/blog/2012/07/09/an-update-on-nested-nib-loading

Storyboard done, Do I need to create .h and .m View Controller file for each View created?

I have created Storyboard with several views calling each other, now I need to create the code
I notice that XCode didn't created .h and .m controller files for each View from storyboard.
Should I create them manually?
Should I keep only one controller? (or few depending of separation of concerns on MVC)
Is there a pattern for developing this?
thanks
The usual approach is one view controller pr. screen full of content. You can imagine having one view controller for a tableview, with any sort of content, and then another view controller that presents that content in a new screen full of content if a row is pressed.
Normally when you have subviews inside of your view controllers, you wire them up in interfacebuilder. Then for instance if you want to populate a view that has a uiimageview and a uiactivityindicatorview inside it, you can control their behavior and how their populated from the view controllers code. You could also if you want something very generic and you feel that one view will probably take up a lot of code in your view controller, create a uiview subclass for it, and then set the class in interface builder.
Did this help? Please let me know if you need more clarification.
It's entirely up to you whether you have a ViewController for each view. If you have many views I would recommend it. Even if you have 2 or 3 views you probably still should. Things can get really confusing when each view has a different task but all have similar IBOutlets.
TLDR; Personally, I would say it was good practice to have a ViewController for each view if each view has a separate task.

How to embed a UIViewController's view from one xib inside a view in another xib?

MyViewController.xib has File's Owner class set to MyViewController (a subclass of UIViewController) and File's Owner view connected to a UIView containing some subviews.
OtherViewController.xib has File's Owner class set to UIViewController and File's Owner view connected to an empty UIView.
Is it possible in Interface Builder to embed MyViewController's view inside the view in OtherViewController.xib?
I tried adding an instance of MyViewController into OtherViewController.xib, but I can't drop it inside the view (because it's not a UIView) and I can't get to the view that was associated with MyViewController in MyViewController.xib (only the view controller itself, and nothing it's connected to, makes it over to OtherViewController.xib).
You probably do not want to do this. Follow the warning in the View Controller Programming Guide:
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.
A UIViewController subclass whose view does not fill the window will not behave as you might expect. It will not receive view controller lifecycle messages, rotation messages, or have its parentView/navigation/tabBarController properties set correctly.
A UITableViewCell should not be the view for a UIViewController. It might have some controller object responsible for managing its behavior (though I suspect this behavior can probably all be contained within the cell view itself) but that controller should not inherit from UIViewController.
This has changed since some of the other answers were posted - you want to take a look at the latest documentation for UIViewController, particularly the guide section "Presenting View Controllers from Other View Controllers" and the class reference guide section "Implementing a Container View Controller". Also, there's a video from WWDC 2012 covering the topic on iTunes: Session 236 - The Evolution of View Controllers on iOS. (The video is very useful, it's not just a general overview.)
You can put it all in one xib. For example, just put it all in your MainWindow.xib.
This can be done programmaticly by adding a reference in OtherViewController to MyViewController. This is perhaps a bit messy and does in some way lead me to ask why you would want to do this but... I will trust that you know what you're doing.
Warning. Because 'Other' will contain a reference to 'My' you will want retain My inside Other. but Do not, I repeat do not retain 'Other' inside of 'My' this kind of cycle will lead to errors.
Good luck and don't forget to vote
ps if you have a little more detail I may be able to help you sort out a better design so that this sort of thing can be avoided :)

View or ViewController... both are views?

In Interface Builder... when I drag a VIEW into the document window... and then double-click on it... it opens and displays the VIEW window. (As expected)
... but when I drag a VIEW CONTROLLER into the document window... and then double-click on it... it also opens and displays the VIEW window, too. (It says "view" right on it.)
Is that right? (Or am I totally misunderstanding things?)
I thought a VIEW was the actual object to draw/drag things into. No?
I thought a VIEW CONTROLLER was just the CODE for your view. No?
I dont have experience with Interface Builder, but a a controller object provides the custom logic needed to bridge the application’s data to the views. In iPhone applications, a view controller is a specific type of controller object that you use to present and manage the views of your application.
Each ViewController has a View property associated to it, which is the one you are seeing in interface builder.
The view stored in this property represents the root view for the view controller’s view hierarchy. Whenever you present the view controller on screen (either modally or as part of view controller–based interface), this view is retrieved and displayed in the application window. The default value of this property is nil
Each view controller object is the sole owner of its view. You must not associate the same view object with multiple view controller objects.
Apple wants you to follow the Model-View-Controller system when you develop apps, and it's pretty straightforward and logical.
The Model is the core of your app. It processes databases, network connections and whatever you need. It's basically custom classes you create in Xcode.
The View is the interface between your app and your users. You can create them in Interface Builder and put them in NIB files (preferably one view every file).
The Controller is the glue between your view and your model. It defines the behavior and state of views (button enabled, label content, etc.) based on what it gets from the model (like a database). It also performs actions on the model based on the events it receives from the views it managers (controls), like changing records in a database or changing variables in objects.
The idea behind all this is that the model can be used in every platform with minimal modification.
Every controller should be linked to one view, and one view only, like a table (UITableViewController) or a screen's view (UIViewController). You subclass the controller you want and you add it to the NIB of the view it's associated with. That's how you do it:
In the NIB, select the File's Owner.
In the Identity inspector, set the class to the view controller you created in your project.
In your custom controller class, create IBOutlets for every view (such as deleteButton) in the associated view you need to have access to. Create and synthesize the properties for every outlet.
Create IBActions for every event you want to register (such as addButtonClicked).
In the NIB, drag a line with your secondary mouse button from the File's Owner to the wanted outlet view and then select which connection you want to make. Repeat until all your IBOutlets are properly connected.
Drag a line with your secondary mouse button from the view you want to register events from to the File's Owner and then select which connection you want to make. Repeat until all your IBActions are properly connected.
Write your code for the controller.

Loading a View from IB

This should be a pretty easy fix, but I haven't figured out from reading the Apple documentation or other SO questions how to do this simple switch from creating my Interface programmatically to using Interface Builder.
I am basing my code around this framework:
http://www.pushplay.net/blog_detail.php?id=27
The only difference is that, where each View is programmatically created (View01.m, View02.m) in ViewDidLoad, I instead want to import from a nib (while still using this framework) for each view (each view has a unique IB design).
Thanks for the help.
Think of IB as an Object Creator and not a code generator. That really helps. What IB does is actually create instances of objects as they are dragged on to the desktop/view/XIB window. It then allows you to start creating various connections (with a control drag on the mouse) from one object to another object. You then instantiate the entire XIB by unarchiving it from your bundle. This is highly automatic and reading up on UIViewController should move you along a bit. Look at:
initWithNibName:bundle:
You basically have two types of connections:
Outlet: This is how you teach one object about the existence of another object. For example, you might have a controller object that needs access to a button. You create an outlet (either in XCode Text Edit in the controller.h file/property area or in IB by adding an outlet) in your controller and then control-click-drag from the outlet to the button.
Actions: This is how you trigger an event on one object to call a method on another object. Actions will have a prototype of:
- (IBAction) someMethod:(id) sender;
I think the ":(id) sender" is optional if your method does not need a link to the object causing the event.
Within IB, you can arrange objects and set various attributes like size, color, position, target/actions, user interactions, Files Owner...
That brings me to files owner. Big concept here. It tends to be the Controller that loads the NIB (OK: I have a custom window controller I have used for over 15 years but Apple has a really good one UIViewController that does all sorts of goodness.) and acts as a proxy in IB. It is not actually instantiated in IB but it will be when you alloc and request it to load the NIB (XIB files are XML files that are turned into NIB files by the compile process)