What are top level objects in an iPhone application nib file?
About the Top-Level Objects
When your program loads a nib file, Cocoa recreates the entire graph of objects you created in Xcode. This object graph includes all of the windows, views, controls, cells, menus, and custom objects found in the nib file. The top-level objects are the subset of these objects that do not have a parent object. The top-level objects typically include only the windows, menu bars, and custom controller objects that you add to the nib file. (Objects such as File’s Owner, First Responder, and Application are placeholder objects and not considered top-level objects.)
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html
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.
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)
Could someone explain the kinds of placeholder objects that may appear in the Interface Builder document window?
The kinds of placeholders that I know exist are: File's owner, First Responder and App Delegate
Links:
This thread explains First Responder.
This thread explains the App Delegate.
iPhone Interface Builder and Delegates: Answers the question, but not very clearly
I copied this from Apple's developer website on Interface Builder, Hope this helps.
Basically in my own words the placeholders hold everything in your program and they consist of everything that the user sees, like a UIView or a UIImageView, something along those lines
Choose Appropriate Controller Objects
In Cocoa and Cocoa Touch nib files, the File’s Owner placeholder object provides the key link between your application and the objects in the nib file. When you load the nib file, you must provide the nib-loading routine with a pointer to the object that should become the File’s Owner. As part of the loading process, the nib-loading code automatically recreates any connections between the object you specify and the nib file objects that have connections to the File’s Owner.
As you design the architecture of your application, it is important to consider which objects you want to manage your nib files. The presence of only one File’s Owner placeholder object is not without good reason. It is usually best to have a single object coordinate the loading and management of a nib file and its contents. This single point of contact provides the desired barrier between your application’s data model and the visual elements used to present that data model and is at the heart of model-view-controller design.
Beyond the File’s Owner object, you can create additional controller objects directly in your nib file to manage subsets of the nib file. Using multiple controllers in this way lets you compartmentalize the window’s behavior into more manageable chunks. For example, if your window has multiple panes of disparate information, you could create separate controller objects to manage each pane. Each controller would continue to go through the File’s Owner to obtain additional information.
In iPhone applications, it is also possible to include placeholder objects besides File’s Owner in your nib file. These additional placeholder objects are almost always used to represent navigation controllers and other view controllers already in use by your application. The presence of these additional placeholder objects does not diminish the role of File’s Owner though. The File’s Owner object is still responsible for coordinating the overall behavior of the nib file’s contents.
I think I provided a thorough answer to this here in a response to this question.
Also, I would call the App Delegate a placeholder. A placeholder is an object that's available in a NIB file for making connections to and from, but isn't instantiated when that file is loaded. So, when you have an orange cube in the MainWindow.xib file with the custom class set to "MyAppDelegate", that causes an instance of "MyAppDelegate" to be instantiated when the NIB is loaded. As a counter example, the file's owner of MainWindow.xib is typically "MyApplication", and an instance of MyApplication won't be instantiated when the NIB is loaded, it's already alloced and initted, and is doing the loading. So, the file's owner is a placeholder for an object that already exists, and the app delegate typically isn't.
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.
As I understand it, I do have to release the top level objects (including window, custom controller objects, ...) from my Nib file, if I load it programmatically by myself.
But do I have to care about them in an simple view-based application that has only one main nib file?
And would I have to care about them when having an view-based application that uses an UITabBarController and multiple Nib files?
No. In all cases, the nibs are loaded once, and then unloaded when your app is closed - you don't have to manage the memory. There's no memory leak possible when you don't create more than one of a given object.