As a newbie, IB and all the possible connections is bewildering to me. Most tutorials I've found are what I'd call the reincarnation of spaghetti code, in which the entanglement is all the connections created by dragging. Of course, I want to use IB for layout of views (sizing & placing visual elements), that's what IB is great for. But a controller is not a view, so it's less confusing if all my controllers are solely code and don't appear anywhere in IB. I suspect this will minimize the spaghetti. It also encourages the one-xib-per-view admonishment. To that end, and here's the question, where can I find example projects that adhere to this strategy?
I don't have a set of sample projects, but I will give you some information about how things work and when you should create controller's in a XIB file or in code.
If your controllers are created dynamically by way of a user's action, you typically won't instantiate them in a XIB file. Instead, you'll instantiate them in code like harms mentions above. Once you do that, you'll still need a mechanism to connect this controller that was created in code, to the user interface elements that you've created in IB.
The mechanism that IB provides for solving this is the File's Owner. Mastering the File's Owner is essential to "getting" Interface Builder.
The file's owner is not an object that is "in" the XIB file, it's an object that's represented in the XIB file. It's a placeholder for an object that will already exist when the XIB file is loaded. When NIB files are loaded at run time, they're loaded with the NSBundle method -[NSBundle loadNibNamed:ownwer:options:]. The owner parameter is used to resolve the file's owner placeholder object in the XIB/NIB file. When the file is loaded at runtime, all of the connections made against the file's owner will resolve against the object you passed in as the owner parameter to the NSBundle method. On the iPhone, you typically don't load NIB file yourself. Instead UIViewController does it for you. The default implementation of UIViewController's loadView method might look something like this:
- (void)loadView {
[[self nibBundle] loadNibNamed:[self nibName] owner:self options:nil];
}
So, by connecting the elements in your XIB file to the file's owner, you'll be connecting them to your view controller.
You will have some controllers that are statically in your application - they'll be alive forever. A navigation or tab controller along with their root items are typically alive for for the entire life of their application. When that's the case, I'd set those view controllers up in the MainWindow.xib file. Most of the other controllers would be created dynamically, and programatically in response the the user doing things.
Good question. The pattern I try to stick with is making the controller in code, adding IBOutlets and IBActions for the things in the XIB/NIB that interact with that code, and a thing in the controller's constructor which loads the XIB/NIB with "self" as the owner, and in IB I connect stuff to the "File's Owner" placeholder, whose identity I will have specified to be the my controller's class.
Related
What happens when we connect the xib objects with class outlets? How to do such connection from code without wiring them in interface builder?
IBOutlets are just instance variables or properties that get set by the nib loading machinery when the nib is loaded at runtime. There's nothing particularly special about them. The trick in setting them up programmatically is finding the object(s) in the nib that you want to connect. If you load the nib using -[NSBundle loadNibNamed:owner:options:] you get an NSArray back containing all the top level objects in the nib (i.e. the objects at the top of the hierarchy in the Document Outline Inspector in IB). You can iterate through these and their subviews to find the objects you want to hook up IBOutlets. Take a look at the Loading Nib Files Programmatically section of the Resource Programming Guide.
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.
How/where in the code does the nib file get related to its *.m and *.h files?
Specifically I'm talking about when you create a new Objective-C class, not using the initWithNibName method.
Wherever this relationship is defined is obviously used by the 'Files Owner' relationship in Interface Builder. I imagine it's a *.plist file somewhere or something.
NIB files describe classes instances.
When you drag and drop a component in a NIB with Interface Builder, actually, you create an instance.
If you drag and drop a UIViewController for instance, and if you did define a subclass of UIViewController in your OWN classes with a .m and a .h, you'll be able to say to interface builder : "use my custom subclass of UIViewController for this object instance".
This is achieved in interface builder with Tools/Identity Inspector and then Class identity : at this place, you can put your own classes that indirectly refer to your own .h and .m
NIB files describe interface. They're produced from XIB files. XIB files are text (XML, to be precise), NIBs are binary. You typically edit XIB files in Interface Builder, and they get compiled into NIBs as the project is built.
.h files contain class interfaces. Interface Builder uses those to compile a list of Objective C classes in your app, and to produce the list of outlets and actions they provide. When you design a XIB, you typically provide one of your ViewController classes as the file owner. Interface Builder would scan a .h file and produce the outlet/action list from it.
.m files contain code. They're not used by the Interface Builder directly. But they can and often do contain code that loads those NIB files. And, of course, they contain code of action handlers.
Although the question is marked as answered, I don't really see the answer that was asked for...
Usually the code itself specifies the relation when creating a view controller, like so:
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
That tells the system to create the view controller instance, and look for "MyView.xib" to load and wire to MyViewController - MyViewController would also have been set to file's owner in the XIB.
Now another way to relate your view controller and the xib, is that in some cases you are actually creating view controller instances in a xib. The tab bar controller is a great example, where for a tab you specify a view controller instance to create, along with the nib name that it will use.
Note this means you can have several xib files that make use of a single view controller, if you want the same controller to with with different kinds of screens. You don't end up doing that often but it can be powerful, when used correctly (it can also be a mess if you try to make one view controller that does too many things).
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)
When I make a sample app (ie, start out with a tab bar application or something), in my MainWindow.xib file, I see 5 items listed -- File's Owner, First Responder, App Delegate, Window, and Tab Bar Controller.
If I make another .xib file, and make a delegate for it, and set that File's Owner to my new delegate that I just made, I do NOT see "NewDelegateFile" in the list of...objects(?) for that .xib.
This doesn't make sense to me, and I think is a huge part of why I'm not catching on all that quickly to iPhone development.
Does anyone care to take the time to explain that little peculiarity to me?
File's Owner is not a real object in the xib file. It is a proxy object. It represents the object that will become the xib's owner when it is loaded. First Responder and App Delegate are proxies also. The first responder is the object currently on top of the responder chain. When the state of the application changes, another object might be the first responder. You use this proxy object to connect things like the File->Save menu to whatever object is responsible handling it at any given time.
The App Delegate is an actual object. It springs to live when the xib is loaded. As you can see in Interface Builder, it is connected to the delegate outlet of file's owner. The Application loads the MainWindow.xib, it is therefor the file's owner.
Other xib file are usually loaded through a delegate object. That delegate object is the file's owner. But the delegate itself is instantiated from code. It is not loaded from the xib. That's why it is not shown in Interface Builder.
xib files contain actual serialized objects. File's Owner and First Responder are exceptions. They represent some other, already existing object.
File's Owner (often a UIViewDelgate in non MainWindow.xib files) is the chicken. The xib is the egg. The chicken itself is not contained in the egg.
A bit long. Hope it helps.