New Method of Getting Items out of Nib Files.
Example in answer below.
This new Answer is the latest change in this project and Question
I want to create a UIView subclass and I want to create an Interface builder file for the UIView. How would I connect the files owner to itself. I want to be able to Design the view and have it create the connections but I dont have a need for a view controller.
Other than loading the nib into an array can I use the nib file as a connector to the view itself ?
I hope i am Asking this properly. I will elaborate tho.
Creating a UIViewController I am given the choice to create an xib file for it. At which time i can add the UIViews to the xib and those connections would be made. However the files owner does not appear to have a UI Editor associated to it so I want to create a UIView that will become a sub view in another view. I dont really want to create it with code because Its a pain to layout the items manually. So I want to use the same construct to create a small uiview to put into another
EDIT:
I Edited this again when I found another even better way to load nib classes. I figured some stack overflow users would want to see this.
I wanted to find an elegant way to load a UIView from a nib. and with some info from stack overflow user PeyloW I have managed to do just that.
I am going to post my results as the information will lead to a solution but this solution feels exceptionally elegant to me.
- First of all, I created a Xib File named "TableViewCells.xib"
(Name Matches the Class Name therefore [[self class] description] == "TableViewCells") - Next I created the Classes that I am using for the views in the Nib. Classes dont matter, Just Make sure the "Custom Class" is selected for the Class Objects in interface builder
- Finally I created the Class "TableViewCells" to match the xib filename
My new Header File.
(Each of the header files imported associate to the items in the single xib file.)
#import <Foundation/Foundation.h>
#import "TitleCell.h"
#import "ToggleCell.h"
#import "ButtonCell.h"
#import "TextCell.h"
@interface TableViewCells : NSObject {
UINib *uiNibHolder;
}
@property (nonatomic, readonly) NSArray *nibArray;
// These are the classes that will be loadable.
- (TitleCell*) titleCell;
- (ToggleCell*) toggleCell;
- (ButtonCell*) buttonCell;
- (TextCell*) textCell;
- (id) loadViewByClass: (id) viewClass;
@end
and the Class file.
loadViewByClass: is the method that finds the item in the nib file.
the convenience accessors have the correct type for the class objects to be instantiated into.
NOTE: I would Not Recommend loading a Bunch of Views into this, the more views you load the more you have to create when you load the nib file.
#import "TableViewCells.h"
@implementation TableViewCells
@synthesize nibArray;
- (void) unloadProperties{
[uiNibHolder release];
}
- (NSArray *)nibArray{
return [uiNibHolder instantiateWithOwner:nil options:nil];
}
- (id) init{
if ((self = [super init]))
{
// Im using the class name for the Xib file.
// This means it will look in TableViewCells.xib
// You can change the class name, or pass a Nib name to this class
uiNibHolder = [[UINib nibWithNibName:[[self class] description] bundle: [NSBundle mainBundle]] retain];
}
return self;
}
- (TitleCell *)titleCell{
return [self loadViewByClass:[TitleCell class]];
}
- (ToggleCell *)toggleCell{
return [self loadViewByClass:[ToggleCell class]];
}
- (ButtonCell *)buttonCell{
return [self loadViewByClass:[ButtonCell class]];
}
- (TextCell *)textCell{
return [self loadViewByClass:[TextCell class]];
}
- (id)loadViewByClass:(Class)viewClass{
for (id item in self.nibArray)
{
if ([item isKindOfClass:viewClass])
{
return item;
}
}
return nil;
}
- (void)dealloc{
[self performSelector:@selector(unloadProperties)];
[super dealloc];
}
@end
Being able to load by class is incredibly nice. And if the class is not in the xib file it will return nil.
This could be adapted to use multiple nib files depending on the type of views you were loading. Using a lazy load property technique you could load those nibs only when needed leaving the memory footprint small and still allowing you to get the classes loaded through one convenient class loader.
As a demonstration I used a TableView to load a handfull of views
@synthesize tableViewCellLoader = _tableViewCellLoader;
- (TableViewCells *)tableViewCellLoader{
if (_tableViewCellLoader == nil){
_tableViewCellLoader = [[TableViewCells alloc] init];
}
return _tableViewCellLoader;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
switch (indexPath.row) {
case 0:
return self.tableViewCellLoader.toggleCell;
break;
case 1:
return self.tableViewCellLoader.textCell;
break;
case 2:
return self.tableViewCellLoader.titleCell;
break;
case 3:
return self.tableViewCellLoader.buttonCell;
break;
}
return nil;
}
As you can see I lazy loaded my TableViewCellLoader and if I wanted to I could make the TableViewCells class lazy load UINib objects only when their classes were called.
I love convenience in code.
And Still, Thanks again PeyloW.
Files Owner is only a proxy object, it is not required to be specified at run-time, but will always be visible at design-time in Interface Builder.
You may ignore hooking anything up to Files Owner if you do not need it. The at run-time load the NIB-file using something like this:
What you pass for the
owner
argument is what passes as the Files Owner proxy when loading the nib,nil
works just fine.The
rootObject
array contains all root level objects, but no proxies. Do note that the array is autoreleased, so if you need the loaded objects to stay around you must retain the array, or just the particular elements you are interested in.Not that using
loadNibNamed:owner:options:
is IO bound. If performance is needed then you should use an instance ofUINib
to cache the NIB file in memory and instantiate objects from it.You can do this, but there is no reason you can't create IBOutlets in your UIView and connect directly to them. So in the xib file you would have a root UIView, make sure you change the class to your custom class. Then you can can set the outlets directly onto the view, you are not required to use the file owner.
Newest Answer by me
After much time and playing with this possibility I have tried a number of scenarios and came to the conclusion that the best possible scenario is to create the UINib for each request and get the object in question. A one time pass gives the best results. If you have an object you plan to make very often it is best to put it into its own nib, rather than in a nib with multiple different classes as each one will be created each time the UINib is initialized.
Here is the class that I use to accomplish this task.
LSObjectLoader.h
LSObjectLoader.m
Finally a couple ways to implement this.
Method 1 Loading Directly.
Method 2 Class loading itself
Nib File "TableViewCells.xib" (Contains a "MyChatCell" class object)
Class File "MyChatCell.h/MyChatCell.m"
Header
Implementation
Method 3 Custom Loader Class
Nib File "MyChatCells.xib" (Contains "MeChat" and "ThemChat" class objects)
Class File "MyChatCells.h/MyChatCells.m"
Header File
Implementation File