What are File Owner and First Responder in iOS - Xcode?
The File Owner is an instantiated, runtime object that owns the contents of your nib and its outlets/actions when the nib is loaded. It can be an instance of any class you like - take a look at the identity tab of the tool palette.
File Owner is the main link between your application code and the contents of the nib file.
For example, consider you have a UIViewController subclass with an IBOutlet for a UILabel. In interface builder the File's owner will be set to the same class as your UIViewController. When your nib is loaded at runtime, the bindings of outlets and actions defined in your nib are bound to the instance of your view controller, as your view controller is the owner.
Nibs are loaded using:
[[NSBundle mainBundle] loadNibNamed:#"NibName" owner:nil options:nil];
The owner parameter is particularly important. That's the runtime instance of a class that owns the contents (outlets, actions and objects) of the nib being loaded.
Hopefully that's clear. To see this at work create a brand new iPhone project with a view controller. Open the Nib file and take a look at the identity tab.
First responder is simply the first object in the responder chain that can respond to events. The responder chain is a runtime collection (or more accurately a hierarchy) of objects that can respond to an event. For example, consider you have a window with a view and on that view is a text field.
If that text field has focus it's known as the first responder in the chain. So if you send a message to the first responder it'll be sent to the text field first. If the text field can't handle the message it'll be sent to the next responder. And the next. And the next, until you get to the end of the responder chain or something has consumed the event (iirc).
The responder chain is worth reading about - hit apple's documentation for more information.
Related
I've followed the instructions in this answer to create a reusable custom UIView laid out with a xib, which I can embed in my Storyboard by referencing the custom class. This works well and I can successfully load the view as advertised. However I want my embedding view controller(s) to be able to connect to IBActions of my embedded view. In the linked example, the custom view receives its own actions but this seems like poor design. I've worked around this by creating a delegate protocol that for custom view, which forwards events to its delegate, but this feels like more work than should be necessary. Additionally, Interface Builder will not allow me to wire up the delegate using references in the UI so I must instead do it programatically.
What I really want is to create a custom IB Action in my custom view, like someActionHappened, then wire that up in the embedding view controller. What is the best way to accomplish this?
A .xib file has a File's Owner, which you can see and select when you're editing it.
When you load the nib, you get to specify the owner.
You can (and must) make the classes of these two things (the File's Owner in the nib and the actual owner at load time) match.
Thus, an action can be hooked from something in the nib to an IBAction in the File's Owner's class, and it will be fulfilled when the nib is loaded. Problem solved.
So:
However I want my embedding view controller(s) to be able to connect to IBActions of my embedded view
So the solution for you is to make your File's Owner (in your nib) and the actual owner (at nib-loading time) be your embedding view controller. Now your embedding view controller is allowed to have an IBAction and you can connect to it in the nib.
I am currently trying to grasp various ios development concepts. I wanted to know what purpose does dragging and attaching the view outlet (from the file owner in Connection Inspector) to the view object serve ? Currently I just think that the way it is done but I would like to know why and what purpose it serves ?
It lets a view controller created in code reference a view inside the nib.
When you load a nib (-[NSBundle loadNibNamed:owner:options:]), you pass an object in the owner parameter. This object becomes the "File's Owner" and has its outlets hooked up as specified in the nib.
The typical UIViewController initializer, -[UIViewController initWithNibName:bundle:], calls the above method with itself as the owner. That's how it gets a reference to the view from nibland.
I have a UIViewController named ViewControllerHome and when the user touches an image on the screen I would like to display a second view which is a Membership Card. I am doing the following from the touch of the image:
membershipCardViewController = [[MembershipCardViewController alloc] initWithNibName:#"MembershipCard" bundle:nil];
[self presentViewController:membershipCardViewController animated:YES completion:nil];
When the code executes an exception is thrown on the presentViewController line.
I have an .xib with a ViewController that contains a view and a UIImageView of the Membership Card. I set the class of the ViewController to my MembershipViewController.
Once that shows up I will dismiss it on a touch.
Can anyone tell me what I am missing? I thought I had all the steps correct to present the view controller.
Thanks for the help.
In the MembershipCardViewController's nib file, its view (what ever view it is controlling) is connected to the view controllers view outlet.
To do this control drag from files owner to the view you want to connect it to (the grey view in this case)
And you should get this:
Files owner should point to your MembershipCardViewController. Every view controller has a pointer to a view. I'm going to guess that you added some custom view after deleting the stock one. Control drag from files owner to that view to make the outlet. (If this outlet returns nil, an exception will be thrown).
To be safe, make sure file's owner (in the nib) is pointing to MembershipCardViewController
(This probably isn't the problem but it sounds like you may have started with an empty nib).
To do this, click on files owner, and select the identity inspector on the right. Make sure the class says MembershipCardViewController
I answered another question before about this Am I right in saying initWithNibName:bundle is used to manually load nib files and that initWithCoder would be used as an alternative?
This explains what is actually going on.
The purpose of your XIB is to archive the view of the controller. Having the controller class set is only part of the required information, you also need to connect any IBOutlet relationships between the controller and the views.
As standard any subclass of UIViewController provides an outlet called view. You need to ensure that it's connected. Otherwise when you load the XIB the view doesn't get set and you get an exception.
There are a number of ways to make the connection. Check this.
See also loaded-nib-but-the-view-outlet-was-not-set-new-to-interfacebuilder.
I followed this UITabBarController Tutorial which creates a Tab Bar with according subviews mostly using Interface Builder. The UITabBarController is created there and the Tab's View Controllers are added there too.
Am I correct that creating the UIViewControllers {WelcomeViewController|AboutViewController}.{h|m} is unnecessary?
Who is the real File's Owner of the Subviews {WelcomeViewController|AboutViewController}.xib?
Note that I at first tried to create an IBAction method in WelcomeViewController.h: in Interface Builder at WelcomeViewController.xib, I could connect a button press to that action as it appeared at File's Owner. But at runtime it crashed, as the real File's Owner presumably is not an Object of WelcomeViewController.m. Am I right here? Is it a bug that the IBAction appears in Interface Builder (Xcode 4 here)?
A last question: How/can I still separate code (having IBActions in WelcomeViewController.h for actions that happen only on this subview) when I connect everything up in Interface Builder like in the tutorial?
Am I correct that creating the UIViewControllers {WelcomeViewController|AboutViewController}.{h|m} is unnecessary?
No, both controllers are necessary, since there should be at least (and, optimally, at most) one ViewController per full-screen window to manage your view hierarchy. The TabBarController is only a kind of "dumb" meta-controller managing the display of the sub-controllers it loads - therefore you need controllers for the views which are switched. I would recommend you read this part of the Apple doc.
Who is the real File's Owner of the Subviews {WelcomeViewController|AboutViewController}.xib?
The File's Owner should be the corresponding controller class (in your case, {WelcomeViewController|AboutViewController}.{h|m}) - you can set the class in Interface Builder in the inspector palette when File's Owner is selected. Only the very first window (usually called Main.xib or so) which is opened at application start should have the application delegate as File's Owner. File's Owners own the objects of the XIB/NIB file - object-reference wise, you know what I mean :) I think it should also be possible to load the XIB/NIB file with other controllers (and the other controller automatically becoming the File's Owner), but I'm not sure.
... Am I right here? Is it a bug that the IBAction appears in Interface Builder (Xcode 4 here)?
It may be that you wired up the action the wrong way in Interface Builder, a common mistake. Try holding the Ctrl key, then drag a line from the button onto the File's Owner, and choose the desired method to link to. That should do it.
A last question: How/can I still separate code (having IBActions in WelcomeViewController.h for actions that happen only on this subview) when I connect everything up in Interface Builder like in the tutorial?
I think I answered this in the first paragraph - WelcomeViewController is still there and all you have to do is create IBOutlets and wire them up in IB. Of course, you can also do the wiring programmatically, since the member "view" is automatically populated (via the File's Owner connection), and all subviews are accessible from there.
I've recently been introduced to development for iOS by a friend and have begun to experiment with the interface builder and view controllers. One thing I'm finding is that when using a nib in conjunction with a view controller, your view controllers ivars are quickly polluted with views you may never actually reference. I would like to modularize the key components in my main nib into several different views. I have two questions regarding this:
How can I create a nib file for a custom sized view (one that doesn't fill the entire screen)?
How can I add the newly modularized to my main nib (all of the classes I would create for the components would be view controllers not views)?
Assuming I were to alloc and init the view controllers and add them to the main view programmatically, how could I position the custom sized views since I have already called initWithNibName:bundle:. I can't call initWithFrame: right?
Answers would be much appreciated!
Thanks,
PhpMyCoder
EDIT
I've discovered the answer to my first question. It seems that in the attributes inspector of your nib file you must disable the status bar (change it to unspecified) to enable the editing of the height and width parameters in the size inspector. However, I still am unsure of how to add these custom nibs and their view controllers to another nib without coding them in with initWithFrame: and addSubview:. Any ideas on adding a view controller's view to a nib in IB?
EDIT 2
Added question 3 (or 2 depending on how you think about it).
EDIT 3
I seem to be hastily asking questions today. A simple call to setFrame: will deal with sizing and positioning (and you can even append it on to your init function initWithNibName:bundle:frame:). Still not sure how to add the view (created by a nib) from a view controller to another nib in Interface Builder. If this is possible, I'd love to hear how.
Remember to not get ViewControllers and Views confused.
They are both in a hierarchy, and each ViewController has/controls a "main" view (which likely has bunches of subviews).
You don't add a view to a nib. A nib is a mechanism to help you assemble views. (A NeXT Interface Builder file, if we delve into nomenclature.)
This is how you load a nib:
[[NSBundle mainBundle] loadNibNamed:#"foo" owner:self options:nil];
Normally, you give a nib name to a controller and it does it for you, but you can do this to. There are complex and tricky ways to access the content. The following is the standard way to do it.
The owner you pass in must be the type declared as the owner in that nib file. It should have some of its outlets connected to objects in the nib file. After you load the nib file, they'll just "be there". If you called this twice, it would overwrite the first ones and replace them with the second ones. (mostly harmless, definitely useless)
So, typically, you wired it up to view. Now you have a view that's floating around in memory and not connected to the view hierarchy of the application. Time to do that. You must take view and figure out where it belongs in the pre-existing hierarchy and call [someOtherView addSubview:self.view] no it, and it will appear. Yes, if you want to explicitly place/size it, you will need to do that. Note that view.frame is in the superview's coordinate system.