If I create an individual nib file and load it in my viewcontroller and assign it to an ivar like so:
self.loadingview=[[[NSBundle mainBundle] loadNibNamed:@"loading" owner:self options:nil] objectAtIndex:0];
Is it possible to create IBOutlets to any thing on it in the nib, like activity indicators? Would File's Owner be the viewcontroller, even though IB wouldn't know this, since it is made an object in code?
Is loading the nib the way I've done it the acceptable practice?
Perhaps the more acceptable practice is to also create a .h/.m, and use that as the class for the XIB, in which case File's Owner is the new custom class; i'd still need to use the above method in my controller, though, when creating the ivar from the custom class, right? Or is there a better way to do all this, without using the controller's xib?
UPDATE: Based on some answers, I did the following. I got rid of the NSBundle
method above, and instead just do this:
@property (nonatomic, retain) IBOutlet UIView*loadingview;
In the nib file for this view, I click on File's Owner and change the Custom Class
to my viewcontroller. Then I control-drag from File's Owner to the View and it links up fine.
I would assume at this point that I now have an ivar in my controller, self.loadingview
that contains the information in the nib. However this isn't the case. I removed the NSBundle method, assuming the controller will now load the nib directly through the IB outlet, but the view in the nib does not show up and I have no control over it in the controller.
I had also removed this when I removed the NSBundle method:
[self.view addSubview:self.loadingview];
I'm not clear how the view actually displays at this point; and if it does, where in the view heirarchy it appears? perhaps it is behind other views. I tried this too:
[self.view bringSubviewToFront:self.loadingview];
But the view just isn't there. In an effort to find it, I did:
//[self.view bringSubviewToFront:self.loadingview];
NSLog(@"index: %i",[[self.view subviews]indexOfObject:self.loadingview]);
both with and without the commented part. I get this:
index: 2147483647
Just because you have created a nib and inside that nib hooked up the outlet on File's Owner does not automatically load that nib from your view controller.
You can use the UINib
class for this:
UINib* nib = [UINib nibWithNibName:@"loading" bundle:[NSBundle mainBundle]];
[nib instantiateWithOwner:self options:nil];
Once you do instantiateWithOwner:self
, the nib will be loaded and self
will be used as the File's Owner and the view from within the nib will be connected to your loadingView
property.
You still need to call [self.view addSubview:self.loadingView]
to add it to the screen.
Interface Builder will know of the file's owner that you sent through the owner:self
argument. What you need to do to make your IBOutlet
s show up in Interface Builder is to set the correct class of the File's Owner in IB under the Identity and Type tab.
Is it possible to create IBOutlets to any thing on it in the nib, like activity indicators? Would File's Owner be the viewcontroller, even though IB wouldn't know this, since it is made an object in code?
They wouldn't be IBOutlets, but yes, you can wire connections by hand. IBOutlet
is an empty macro. It exists exclusively so that Interface Builder can find the properties you would like it to wire to. But the IBOutlet
keyword has absolutely no impact on the runtime (it's not even seen by the compiler). Similarly IBAction
is a macro that is replaced with void
. Nothing about Interface Builder exists at runtime.
When the nib loader reads the nib file, it deserializes each object and then for each connection, it sends a setter message (setFoo:
) to the connection target passing the new object. After it has finished that for every object in the nib file, it sends awakeFromNib
to every object it created. Objects with a connection target of nil
are sent to the "owner" (which is self
in your example). Note that the file owner is not created by the nib loader. The nib loader has no control over the actual class of the file owner. It's up to you to make sure that the file owner responds to the set...:
calls or you'll crash.
Is loading the nib the way I've done it the acceptable practice?
I would not rely on loadingView
being the first top-level object. The order of objects is not defined. Instead, you should use IB to wire the view to the loadingView
property of File Owner.
Perhaps the more acceptable practice is to also create a .h/.m, and use that as the class for the XIB, in which case File's Owner is the new custom class; i'd still need to use the above method in my controller, though, when creating the ivar from the custom class, right? Or is there a better way to do all this, without using the controller's xib?
The traditional way to do it is to have a UIViewController
for each nib file in iOS. But that's isn't required. On Mac, NSViewController
is pretty new and doesn't work as well as UIViewController
, so there isn't as strong a tradition there. Hand-loading like I'm describing is more common there, though most things are still handled through NSWindowController
.
If you want to do these kinds of things, Nib Files in the Resource Programming Guide is required reading.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With