views:

42

answers:

2

When I make an object to use in NIB, the object should implement -initWithCoder:. However I can't figure out regular pattern implementing this.

I have been used this code.

- (id) initWithCoder:(NSCoder *)aDecoder
{
 if(self=[super initWithCoder:aDecoder])
 {
     // initialize my object.
 }
 return self;
}

But I have to make same code for UIView instantiated by code like this.

- (id) initWithCoder:(NSCoder *)aDecoder
{
 if(self=[super initWithCoder:aDecoder])
 {
     // initialize my object.
 }
 return self;
}
- (id) initWithFrame:(CGRect)frame
{
 if(self=[super initWithFrame:frame])
 {
     // initialie my obejct.
 }
 return self;
}

I feels something wrong. Any recommendations?

*Of source the initialization logic can be extracted into a new method, but it's not a point.

+2  A: 

Use awakeFromNib to initialize a UIView that's being created from a NIB file. If you want to make it general so that it can be created either from a NIB file or programmatically, make a method like configureObject and call it from both the designated initializer (often initWithFrame:) and from awakeFromNib.

- (void)configureObject {
    // Do initialization here
}

- (id)initWithFrame:(CGRect)frame {
    if(self = [super initWithFrame:frame])
    {
        [self configureObject];
    }

    return self;
}


- (void)awakeFromNib {
    [self configureObject];
}
Jacques
A: 

Apart from Jacques answer, which is the correct way to solve this problem, you had a logic error. In your initWithCoder you have set self = [super initWithCoder:aDecoder]; and then you do return [self init];. In init, you again overwrite self through self = [super init];, potentially reversing things you have done in initWithCoder:. And again in init, you have return [self init]; which causes an endless recursion until the stack overflows.

The pattern for init methods is something like this:

- (id) initWithFoo:(Bar *)baz {
    if ((self = [super initWithFoo:baz])) {
        // Do custom initialization.
    }

    return self;
}

or:

- (id) initWithFoo:(Bar *)baz {
    if ((self = [super initWithSome:baz other:@"signature"])) {
        // Do custom initialization.
    }

    return self;
}

Also, a bit of clarification: - (id) initWithCoder:(NSCoder *)aDecoder gets called on deserialization. In this case on deserialization done by loading a NIB/XIB. There is a counterpart, - (void)encodeWithCoder:(NSCoder *)encoder. Read the Archives and Serialization Programming Guide, you might find that useful if you want to store objects on disk or want to transmit them over a network.

Anyway, with NIBs, once they are loaded the awakeFromNib method is called for each object that is stored inside a NIB and it serves as a kind of second-level-initializer.

Then, there's initWithFrame:. This is the designated initializer and the one you call when creating UIView instances programmatically.

DarkDust
Oh sorry. It was my mistake not to check sample code. I updated my question :)
Eonil