Put a UIView into a UITableView Header - iphone

I have a UITableView which is in my xib file. And I created a property like this for the controller:
#property (nonatomic, retain) IBOutlet UITableView *myTableView;
Now, I want to have a table view header (not a header for each section). So, because I want to have custom styling, I created a new xib file with a view (and I connected to my controller which has the myTableView implemented).
Then I can write in viewDidLoad in my controller:
[self.myTableView setTableHeaderView:self.myTableHeaderView];
where myTableViewHeader is a UIView property in the controller.
Unfortunately, the UITableView won't display this UIView, so my question is, how can I put a UIView to a UITableView into the header?
Thank you in advance & Best Regards.

A couple of things to check:
myTableHeaderView must also be an IBOutlet or created in code in your Class somewhere
self.myTableHeaderView must not be nil when you're trying to add it as the table header view. If it is nil then you didn't hook up your outlets correctly
if you've designed the table view header in IB in its own .xib file, then you must somewhere call this (viewDidLoad is a good place):
[[NSBundle mainBundle] loadNibNamed:#"MyTableViewHeader" owner:self options:nil];
The File's Owner of the MyTableViewHeader.xib must be your TableViewController subclass, and you must hook up the myTableHeaderView object to File's Owner's corresponding outlet.
EDIT: in answer to "what does [[NSBundle mainBundle] loadNibNamed:#"MyTableViewHeader" owner:self options:nil];" do?
This one little line contains the magic that will open your eyes to how XIB files and Objective-C objects work together in Cocoa (touch), elevating your iOS programming kung-fu to entirely new levels. There are two classes of Cocoa programmers, those who understand what it does and use and benefit from it, and those who don't yet know what they're missing, and instead stumble through the wilderness trying to create XIB files for their objects and never quite getting it to work.
With that massive build-up here's the details:
A XIB (NIB) file is a collection of archived Objective-C objects (and reference to objects not actually within the XIB, like "File's Owner", a so-called "proxy object") and connections between these objects. When a XIB file is loaded, these archived objects are brought to life in exactly the state they were saved into the XIB, and then the connections between those live objects (and "proxy objects") are made according to the connections recorded in the XIB file.
For example, in your standard UIViewController subclass .xib file, you have File's Owner set to your MyViewController class. Inside the .xib is a UIView object, which usually itself contains other UIKit objects. The "view" outlet of the UIViewController class is set to point to the UIView object in the .xib. When this .xib file is loaded, the UIView object is unarchived and becomes a living UIView object, with all of the properties and settings recorded in the .xib. That's the "unarchiving part".
And then, because of the connection in the .xib from File's Owner (MyViewController class) to the UIView object, the pointer to this new UIView object is stored in the "view" field of your MyViewController instance. Any other connections also present in the .xib file, like UILabels, UIButton actions, etc., are also set up, to any other "IBOutlet" fields in MyViewController.
This all seems like magic and happens with the
(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
method when you init a new UIViewController subclass.
Now the good part: you get to do this sort of associating nib files with objects yourself! You can use the loadNibNamed:owner:options method to associate any .xib file with matching set of nil IBOutlets in any object that you want!!!
All of a sudden, creating entirely custom table view cells, table headers, footers, whatever, is a breeze, you can easily write modular reusable UIView components, etc., all laid out in Interface Builder.
The object whose nil IBOutlets you want to fill in with objects loaded from a .xib file is the "owner" object. Usually (but I'm not sure this is absolutely required, any class with the identically typed and named IBOutlets set to File's Owner may work), this is the class that will be specified as "File's Owner" in the xib.
OK, now you've got your existing owner object with nil IBOutlets (the IBOutlets must be nil or they won't be changed, that's the "rule" of loading XIBs into an owner object. It's ok that some IBOutlets are not nil, they just won't be changed when you load the XIB file, and usually that's what you want), and you've got your .xib file with objects that you want to load into the owner object. You call:
[[NSBundle mainBundle] loadNibNamed:#"MyXIBFileToLoad" owner:theOwner options:nil];
.. and voila! Now any nil IBOutlets in "theOwner" that are connected to objects in the MyXIBFileToLoad.xib have been set to the new objects loaded from the XIB file.
(also, this method returns an array of all objects unarchived from the xib. If you don't care about setting any owner's outlets, you can just search this list for your objects by class and by tag).
So that's the story, now go crazy with new ways to associate Objective-C classes with objects stored in XIB files!

Related

awakeFromNib is not calling but displaying xib

I have created a new project in xcode 4.5 and I have called my viewcontroller by
-(id)initWithNibName:bundle:
from appdelegate as it called in default project template and i am not using storyboard
but awakeFromNib was not called
I have also searched but not able to understand why awakeFromNib is not calling.
By apple documentation for -(void)awakeFromNib
"Prepares the receiver for service after it has been loaded from an Interface Builder archive, or nib file."
"Objects that conform to the NSCoding protocol (including all subclasses of UIView and UIViewController) are initialized
using their initWithCoder: method. All objects that do not conform
to the NSCoding protocol are initialized using their init method. After all objects have been instantiated and
initialized, the nib-loading code reestablishes the outlet and action connections for all of those objects. It then
calls the awakeFromNib method of the objects."
My question is that Why awakeFromNib is not calling when xib file is loaded?
Is i am doing something wrong?Please elaborate
awakeFromNib: is called only if the view controller is inside the nib file.
In this case you init the view controller with init initWithNibName:bundle, so the content of the view controller is inside the nib, not the view controller itself.
If you open the xib file, drag an object inside the xib and set the class to be your view controller class name, then awakeFromNib will be called (this case you don't need to initialize manually the view controller).
So keep in mind the difference between having a view controller in a xib file, and having a view controller not in a xib file, but with all it's contents loaded from a xib file.
PS: I used nib and xib interchangeably.
EDIT
I forgot to tell you how to go around this.Override viewDidLoad to do things with the initialized outlets.
Why not just add the -(id)initWithNibName:bundle: method to your subclass instead of -(void)awakeFromNib?
My "awakeFromNib" methods are called just fine but I load my view controller with:
myViewController *vc = [[[NSBundle mainBundle] loadNibNamed:#"myViewController" owner:self options:nil] objectAtIndex:0];
so I'm wondering if your awakeFromNib isn't called because you're using initWithNibName instead?
EDIT: I just saw your comment that you're adding the awakeFromNib to the ViewController of the default project that is created by XCode. Did you uncheck the "use StoryBoard" box when you created your project? If your nib is inside of the project's main storyboard, there may be some extra hoops you have to jump through.

Two UIViewController, one XIB File

Let's say, I have three UIViewController
UserFormViewContoller
NewUserFormViewController : UserFormViewController
UpdateUserFormViewController : UserFormViewController
So, NewUserFormViewController and UpdateUserFormViewController view controller inherit from it's parent to share the basic functionality. The different will be their method, create and update.
The views also have a lot of things in common, almost everything. The different view components between NewUserFormViewController and UpdateUserFormViewController is a button to perform save task (create or update)
Is it possible to have two UIViewController sharing one XIB file? Let's say, UserFormViewController.xib and then I do
[[NewUserFormViewController alloc] initWithNibName#"UserFormViewController" bundle:nil];
[[UpdateUserFormViewController alloc] initWithNibName#"UserFormViewController" bundle:nil];
The other question but important is, when I edit xib file with Interface Builder, what owner's reference outlets and IBActions is it talking about, NewUserFormViewController or UpdateUserFormViewController?
(IBActions and Outlets showing when we right click at the Placeholders -> File's Owner)
If that's so, I will just use one XIB file and programmatically add other specific view component (It would be great to have only one XIB file so that I can make some changes at a place but effective on both)
The "file owner" is just a convention so that XCode can show you the correct IBOutlets and IBActions in its inspectors. If you create a generic (in OO terms: abstract) UserFormViewController (.h, .m, .xib), wire it in IB; then subclass it in two NewUserFormViewController and UpdateUserFormViewController, they'll inherit their outlets and actions from their parent class without any problem.
#Armaan I met the same problem by simply call subclass' alloc init method. I fixed this problem by using initWithNibName: and supply xib file name of parent class.

iPhone Having Two Views associated with ONE view controller

Blarg!
I'm trying to develop a game with zelda-like qualities. (i.e. When the PC hits the edge of the screen, the screen changes to the next view, and the PC's position restarts at the appropriate edge.)
The problem I'm having is that I don't want to have multiple View Controllers for each level-segment, because all of the data/functionality exists in the original "LevelView" controller. How do I retain the code from this "LevelView" controller, while only switching NIB files? (i.e. The only classes that I want to be there are the AppDelegate, "LevelView", "ItemView", etc.) I don't want to have to re-create a view controller for each NIB file in the game.
I appreciate any help you can offer! Thank you very much! :D
Create a NIB file that has just the new view in it. Change the class of the File's Owner in the NIB file to the class of the LevelView controller. When you want to load a new NIB file, call the following code from the LevelView controller:
NSArray *topLevelObjects = [[[NSBundle mainBundle] loadNibNamed:#"Put your nib file name here" owner:self options:nil];
UIView *newLevelView = [[topLevelObjects objectAtIndex:0] retain];
What is this doing? When you call loadNibNamed, it returns to you an array of the top-level objects in the NIB file. The "File's Owner" and "First Responder" proxy objects don't count as top-level objects. So, you'll get an array with just the top-level view in the NIB file. You pass self as the file's owner so that any outlet connections you make between the subviews of the top-level view and the "File's Owner" in interface builder get connected.
If you connect the top-level view to an outlet in your view controller, you don't need to do anything with the array loadNibNamed returned. Just ignore it and it'll get released automatically (it gets returned to you with a retain count of 0).
Now, I think doing things this way is a bad idea. I think there are better ways to design your app. For example, it probably makes more sense to create a data file (a property list or XML file for example) that describes the levels than to put all of the levels into NIB files. But, if you really want to do this, the stuff above should get you started.
Use NSUserDefaults and get it from there.

Multiple XIBs same File's Owner

I am trying to create a two view, single controller application as follows: I have two XIB's. Each with the same File's Owner.
As a test, I have placed a UILabel on each XIB. I have connected the File Owner to the UILabel in each XIB. The outlet property is the same.
When I instantiate the nib using loadNibNamed I also set the 'owner' to the instance of File's Owner, e.g.:
nib=[[NSBundle mainBundle] loadNibNamed:#"ONE" owner:OWNER options:nil];
nib=[[NSBundle mainBundle] loadNibNamed:#"TWO" owner:OWNER options:nil];
Now, in OWNER, if I call
[myLabel setText:#"Hello World"];
I see the label update only in nib TWO.
If I create additional UILabels that are unique to each NIB then I can properly update and view them. It seems that I can only have one connection from the property on File's Owner to each NIB.
Any ideas?
What you want is an IBOutletCollection. That allows you to assign a property to more than one nib element, and talk about the entire group all at once.
an IBOutlet can only point to one object. You will need two of every IBOutlet you want to use.
This is very old and not much viewed, but I can't help but notice why this doesn't work. You're passing in the same instance of the owner. Make two instances of the file's owner and you can have two different label values. There's no reason you couldn't assign all of your outlets in your whole project to one Object class in fact, although you probably wouldn't want to do this. Another thing to think about is whether you shouldn't be using inheritance here, by making a superclass, connecting all of the common outlets to that class and then a subclass with unique outlets. Indeed, since you will either have to distinguish your nibs by calling them by nib identifier or by a the class associated with them I think it's better practice to associate separate classes and use inheritance to cover the overlap between them.

Arbitrary objects to handle actions?

My question may be a bit stupid, but why can't any object instantiated in IB handle, say, button click? I mean I'm able to add my own object to a xib, and link outlets to cotrols and control actions to object's method, but once I press the button everything just crashes (uknown selector).
Do you guys have a hint around that?
EDIT: The code, as requested:
#interface TextController {
IBOutlet UILabel * textLabel;
IBOutlet UITextField * textField;
}
-(IBAction)buttonClicked:(id)sender;
#end
#implementation TextController
-(IBAction)buttonClicked:(id)sender {
textLabel.text = #"Ololo";
}
#end
Connections in IB are ok, just believe me. It's really hard to get them wrong with all this drag'n'drop stuff :)
EDIT 2: TextController is not a file owner (in this case it works fine). However, I just want to understand why I can't wire up an action to some object (may be even not a subclass of UIViewController).
You can wire outlets and actions to any object in the nib-file. Drag an NSObject form the library palette onto your nib-file, in Interface Builder. Then go to the Identity tab of the information palette and set the Class of your object.
This way you can instantiate any object of any class from your nib. If the target you want to hook to is statically created from the nib-file. Make sure that the file's owner have at least one reference to your object, or else it will be deallocated as soon as it has been created. Targets are not retained by the sender.
If the object you want to hook up should not be statically created from your nib, then implement awakeFromNib in a class that is instantiated from the nib-file and hook up the targets in code.
Last option is if you do not have any sub-class of your own in the nib-file at all. Then implement initWithNibName:bundle: in your UIViewController subclass, and hook up your targets in code after calling the super implementation.
post code, this usually means you dont have your connections wired up correctly. Is file's owner TextController in IB?