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

时间:2010-05-31 16:37:17

标签: iphone initialization archiving

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

根据 Apple

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

但Apple也说一个类应该有一个指定的初始值。

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

1 个答案:

答案 0 :(得分:28)

苹果说:

  

指定的初始化程序初始化程序...   具有 主要 责任的方法   用于初始化a的新实例   类。每个类定义或继承   它自己的指定初始化程序。   通过消息自我,其他   init ...同一个类中的方法   直接或间接调用   指定的初始化程序,和   指定的初始化程序,通过   消息到超级,调用   指定的初始化程序   超类。 [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;
}

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

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

Edit01

来自评论:

  

特别是,如何传递值   对于我的一些伊娃来说   初始化正在发生   的initWithCoder?

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

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

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

如果在冻结它时没有保存整个对象,则实例对象不存在不需要冻结的属性。 < / strong>

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

要内联指定的初始值设定项,首先解码,然后调用指定的初始值设定项。像这样:

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

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

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

这是最简单的情况。如果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;
}

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

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