iPhone - initWithCoder是通常指定的初始化设计模式的例外吗?

Wil*_*sch 16 iphone initialization archiving

我有一个MyClass类.它有实例变量passInVar1,passedInVar2等,其值将从请求初始化的对象传入.它还有实例变量decodingVar1,decodingVar2等,它们将从存档中解码 - 或者如果没有存档则设置为默认值.

根据Apple的说法,

当一个对象收到initWithCoder:消息时,该对象应首先向其超类发送消息(如果适用)以初始化继承的实例变量,然后它应该解码并初始化它自己的实例变量.

但Apple还说一个类应该有一个指定的初始化程序.

处理所有这些问题的最佳方法是什么?

Tec*_*Zen 28

苹果说:

指定初始值设定项初始化类的新实例的主要负责的init ...方法.每个类定义或继承自己的指定初始化程序.通过对self的消息,同一类中的其他init ...方法直接或间接地调用指定的初始化器,并且指定的初始化器通过对super的消息调用其超类的指定初始化器.[emp补充]

原则上,指定的初始化程序是所有其他init方法调用的一个init方法.但是,它不是唯一的init方法.每个班级都不得拥有自己的班级.实际上,在实践中,指定的初始化程序实际上是超类'init.

主要功能initWithCoder是允许从存档对象进行初始化.对于需要某些特定数据的类,它的指定初始化程序将接受该数据.initWithCoder然后只需解压缩存档,然后调用指定的初始化程序.

例如,UIView的指定初始化程序是initWithFrame:.所以,UIView initWithCoder看起来像:

- (id)initWithCoder:(NSCoder *)decoder{
    CGRect theFrame= //...uppack frame data
    self=[self initWithFrame:theFrame];
    return self;
}
Run Code Online (Sandbox Code Playgroud)

指定初始化程序的要点是创建一个所有初始化必须通过的中心点,以确保每个实例都完全初始化,无论数据来自何处或初始化的情况如何.

这绝不应该意味着一个类只能有一个初始化方法.

Edit01

来自评论:

特别是,当通过initWithCoder进行初始化时,如何传递我的一些ivars的值?

好吧,你没有.initWithCoder的重点在于您正在处理类的冻结实例,其中包含重新创建对象所需的所有数据.

NSCoding协议使您的课程表现得像他们在漫画书中作为"海猴"出售的盐水虾.编码方法使盐水 - 虾/实例脱水/冷冻干燥.解码方法为盐水虾/实例提供水合,就像将盐水虾倒入水中一样.就像盐水虾除了水一样,它们具有开始生活所需的一切,保存在磁盘上的编码对象具有在用编码器初始化后重建自身所需的所有数据.

这个规范的例子是一个nib文件.nib文件只是一堆UI元素和控制器的冻结实例.UIViewController及其在nib中的UIViews具有初始化所需的所有数据,这些数据编码为nib文件的xml.当您initFromNib直接或使用IBOutlet调用时,它会调用每个类的intiWithCoder:方法.

如果在冻结时不保存整个对象,则实例对象不存在不需要冻结的属性.

您只需在初始化对象后设置这些辅助属性.

要内联指定的初始值设定项,您只需先解码,然后调用指定的初始值设定项.像这样:

-(id) initWithRequiredValue:(id) someValue otherRequiredValue:(id) anotherValue{
    if (self=[super init]){
        self.requiredProperty=someValue;
        self.anotherRequiredProperty=anotherValue
    }
    return self;
}
Run Code Online (Sandbox Code Playgroud)

如果超类不支持NSCoder,那么你自己在子类中启动它:

- (id)initWithCoder:(NSCoder *)decoder {
    id someDecodedValue=[decoder decodeObjectForKey:@"someValueKey"];
    id someOtherDecodedValue=[decoder decodeObjectForKey:@"someOtherValueKey"];
    self=[self initWithRequiredValue:someDecodedValue otherRequiredValue:someOtherDecodedValue];
    return self;
}
Run Code Online (Sandbox Code Playgroud)

这是最简单的情况.如果super本身支持NSCoding,那么你通常最终会编写一个并行指定的初始化器,如下所示:

- (id)initWithCoder:(NSCoder *)decoder {
    if (self=[super initWithCoder:decoder]){
        id someDecodedValue=[decoder decodeObjectForKey:@"someValueKey"];
        id someOtherDecodedValue=[decoder decodeObjectForKey:@"someOtherValueKey"];
        self.requiredProperty=someDecodedValue;
        self.anotherRequiredProperty=someOtherDecodedValue;
    }
    return self;
}
Run Code Online (Sandbox Code Playgroud)

我认为在大多数情况下,initWithCoder最终会成为并行指定的初始化程序,因为它会像指定的初始化程序一样处理所有初始化.它看起来不像指定的初始化程序,因为它的所有数据都是由编码器提供的,但它执行相同的功能.

这是理论和实践不能很好地排列的案例之一."指定的初始化程序"概念实际上仅适用于从头开始创建实例的情况.

  • ``Uitiew`的`-initWithFrame:'不被`-initWithCoder`调用.请参阅http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html"如果使用Interface Builder设计界面,则在查看对象时不会调用此方法随后从nib文件加载." (5认同)