Reputation: 1782
I have some custom created UIViews that use .xib files for layout, and backing classes for extra setup. I create these classes using alloc/init and calling loadNibNamed in my custom init method but in doing so was causing memory leak. Someone pointed out that the alloc portion actually created a self object that was leaking so I adjusted my init method to this one:
- (id)init
{
[self autorelease];
self = [[[[NSBundle mainBundle] loadNibNamed:@"AssignmentView" owner:nil options:nil] lastObject] retain];
[self setupBranding];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapDetected:)];
[self addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
return self;
}
However, now when I run analyze code I get this warning "Returning 'self' while it is not set to the result of '[(super or self) init...]'". So my question is what is the correct way for doing custom UIViews with a backing class?
Since it was asked I'd used this above code like this:
AssignmentView * assignmentView = [[AssignmentView alloc] init];
[self.view addSubview:assignmentView];
Upvotes: 9
Views: 15839
Reputation: 8845
Get the view from -[NSBundle loadNibNamed:owner:options:],
then set its frame to match your view's bounds. Generally you'll also want to make the view in the nib resize when its parent view is resized.
We've got a UIView category with these additions:
- (UIView *)viewFromNib
{
Class class = [self class];
NSString *nibName = NSStringFromClass(class);
NSArray *nibViews = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];
UIView *view = [nibViews objectAtIndex:0];
return view;
}
- (void)addSubviewFromNib
{
UIView *view = [self viewFromNib];
view.frame = self.bounds;
[self addSubview:view];
}
Then our -initWithFrame: method looks like this:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self addSubviewFromNib];
}
return self;
}
Just make sure the nib has the same name as the class for this to work.
Upvotes: 19
Reputation: 42588
Would you consider using the convenience constructor style?
+ (AssignmentView *)assignmentView
{
AssignmentView *result = [[[NSBundle mainBundle] loadNibNamed:@"AssignmentView" owner:nil options:nil] lastObject];
[result setupBranding];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapDetected:)];
[result addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
return result;
}
It gives you the flexibility you seem to need when construct your view, but doesn't cause a memory leak or warnings.
Upvotes: 7