UIView and initWithFrame and a NIB file. How can I get the NIB file loaded?
Solution 1:
You have many options, depending on how your "baseView" class is meant to be used and integrated in to your application. It's not clear just how you intend to use this class -- as the view in a UIViewController subclass, or as a reusable modular component mean to be instantiated multiple times throughout your application, for use in many different view controllers.
If your view is meant to be the only view in a UIViewController subclass, then Phonitive is correct -- bundle it together with the UIViewController subclass .xib file and use the UIViewController's viewDidLoad to do final initialization.
But if you want your View class to be a subcomponent reused multiple times in different view controllers, integrated either via code or via inclusion in a .xib file for another controller, then you need to implement both the initWithFrame: init method, and awakeFromNib, to handle both cases. If your internal initialization always includes some objects from .xib, then in your initWithFrame you'll need to load your .xib manually in order to support "customer" classes that want to create your widget via code. And likewise, if a .xib file contains your object then you'll need to make sure you call any code-required finalization from awakeFromNib.
Here's an example of how to create a UIView subclass component with the UI design in a nib.
MyView.h:
@interface MyView : UIView
{
UIView *view;
UILabel *l;
}
@property (nonatomic, retain) IBOutlet UIView *view;
@property (nonatomic, retain) IBOutlet UILabel *l;
MyView.m:
#import "MyView.h"
@implementation MyView
@synthesize l, view;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code.
//
[[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
[self addSubview:self.view];
}
return self;
}
- (void) awakeFromNib
{
[super awakeFromNib];
// commenters report the next line causes infinite recursion, so removing it
// [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
[self addSubview:self.view];
}
- (void) dealloc
{
[l release];
[view release];
[super dealloc];
}
Here's what the nib file looks like (except that file's owner needs to be changed to MyView class).
be sure to hook up both the view and label outlets to File's Owner. That's it! A template for creating re-usable UIView widgets.
The really neat thing about this structure is that you can place instances of your MyView object in other nib files, just place a UIView at the location/size you want, then change the class in the identity inspector (CMD-4) to MyView, and boom, you've got an instance of your widget in whatever views you want! Just like UIKit objects you can implement delegate protocols so that objects using your widget can be notified of interesting events, and can provide data to display in the widget to customize it.
Solution 2:
I found this post after having a problem trying to do this in my app. I was trying to instantiate the view from a NIB in the ViewDidLoad method, but the controls acted as if they were disabled. I struggled with this trying to directly set the userInteractionEnabled property and programmatically set the touch event selector for a button in this view. Nothing worked. I stumbled upon another post and discovered that viewDidLoad was probably too soon to be loading this NIB. I moved the load to the ViewWillAppear method and everything worked. Hope this helps someone else struggling with this. The main response was great and works well for me now that I have it being called from the proper place.
Solution 3:
if you want to use a NIB, it's better for your UIView to be linked with a UIViewController, in this case you can use
UIViewController *vc=[[UIViewController alloc] initWithNibName:@"YourNIBWihtOUTEXTENSION" bundle:nil]
[self.view addSubView:vc.view ];
becareful of memory leaks, you have to release vc