在子类化UIView时,实现`-init`链的常规模式是什么?

时间:2010-10-07 06:00:34

标签: objective-c cocoa-touch design-patterns

当我在NIB中创建一个对象时,该对象应该实现-initWithCoder:。但是,我无法弄清楚实现这一点的常规模式。

我已经使用过此代码。

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

但我必须为像这样的代码实例化的UIView制作相同的代码。

- (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;
}

我觉得有些不对劲。有什么建议吗?

*在源代码中,初始化逻辑可以被提取到一个新方法中,但它不是一个点。

2 个答案:

答案 0 :(得分:4)

使用awakeFromNib初始化从NIB文件创建的UIView。如果你想使它成为通用的,可以从NIB文件或以编程方式创建,可以创建一个类似configureObject的方法,并从指定的初始化程序(通常是initWithFrame :)和awakeFromNib中调用它。

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

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

    return self;
}


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

答案 1 :(得分:1)

除了雅克回答,这是解决这个问题的正确方法,你有一个逻辑错误。在initWithCoder您设置self = [super initWithCoder:aDecoder];,然后执行return [self init];。在init中,您再次通过self = [super init];覆盖自我,可能会颠覆您在initWithCoder:中所做的事情。再次在init中,你有return [self init];导致无限递归,直到堆栈溢出。

init方法的模式是这样的:

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

    return self;
}

或:

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

    return self;
}

此外,还有一点澄清:- (id) initWithCoder:(NSCoder *)aDecoder在反序列化时被调用。在这种情况下,通过加载NIB / XIB完成反序列化。有一个对应的- (void)encodeWithCoder:(NSCoder *)encoder。阅读Archives and Serialization Programming Guide,如果您想将对象存储在磁盘上或想通过网络传输它们,您可能会觉得很有用。

无论如何,对于NIB,一旦加载,就会为存储在NIB中的每个对象调用awakeFromNib方法,并且它充当一种二级初始化器。

然后,有initWithFrame:。这是指定的初始化程序,也是以编程方式创建UIView实例时调用的初始化程序。