iPhone - initWithCoder 是通常指定初始化程序设计模式的例外吗? [英] iPhone -- is initWithCoder an exception to the usual designated initializer design pattern?

查看:45
本文介绍了iPhone - initWithCoder 是通常指定初始化程序设计模式的例外吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个班级 MyClass.它有实例变量passedInVar1、passedInVar2 等,其值将从请求初始化的对象传入.它还具有实例变量 decodedVar1、decodedVar2 等,这些变量将从存档中解码——如果没有存档,则设置为默认值.

I have a class MyClass. It has instance variables passedInVar1, passedInVar2, etc. whose values will be passed in from the object that requests the initialization. It also has instance variables decodedVar1, decodedVar2, etc. that will be decoded from an archive -- or set to a default value if there is no archive.

根据 苹果,

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

但 Apple 也表示,一个类应该有一个指定的初始值设定项.

But Apple also says that a class should have a single designated initializer.

处理这一切的最佳方法是什么?

What is the best way to deal with all of this?

推荐答案

Apples 说:

指定初始化器初始化...具有主要责任的方法用于初始化 a 的新实例班级.每个类定义或继承它自己指定的初始化程序.通过给自己、其他人的信息init... 同一个类中的方法直接或间接调用指定的初始化器,以及指定的初始化器,通过给 super 的消息,调用其指定的初始化器超类.[emp 添加]

designated initializer The init... method that has primary responsibility for initializing new instances of a class. Each class defines or inherits its own designated initializer. Through messages to self, other init... methods in the same class directly or indirectly invoke the designated initializer, and the designated initializer, through a message to super, invokes the designated initializer of its superclass. [emp added]

原则上,指定的初始化器是所有其他 init 方法调用的一个 init 方法.但是,它不是唯一的 init 方法.每个类也不必有自己的.在实践中,更常见的是指定的初始化器实际上是超类的 init.

In principle, the designated initializer is the one init method that all other init methods call. It is not, however, the only init method. Neither does each class have to have its own. More often in practice the designated initializer is actually the super class' init.

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

The major function of initWithCoder is to allow for initialization from an archived object. In the case of a class which requires some specific data, it's designated initializer will accept that data. initWithCoder then simply unpacks the archive and then calls the designated initializer.

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

For example, the designated initializer for UIView is initWithFrame:. So, UIView's initWithCoder looks something like:

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

指定初始化器的重点是创建一个所有初始化都必须经过的中心点,以确保无论数据来自何处或初始化环境如何,每个实例都被完全初始化.

The point of the designated initializer is to create a central point that all initialization has to pass through in order to ensure that each instances is completely initialized regardless of where the data came from or the circumstances of the initialization.

这不应该被理解为一个类只能有一个初始化方法.

That should never be taken to mean that a class can only have one initializer method.

来自评论:

特别是,我如何传递值对于我的一些 ivars 在什么时候初始化是通过initWithCoder?

In particular, how do I pass values for some of my ivars in when initialization is happening via initWithCoder?

嗯,你没有.initWithCoder 的全部意义在于您正在处理类的冻干实例,其中包含重新创建对象所需的所有数据.

Well, you don't. The entire point of initWithCoder is that you are dealing with a freeze dried instance of your class that contains all the data necessary to recreate the object.

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

The NSCoding protocol makes your class behave like the brine shrimp they sell as "Sea Monkeys" in the comic books. The coding methods dehydrates/freeze dries the brine-shrimp/instances. The decoding methods hydrates the brine-shrimp/instances just like pouring the brine shrimp into water does. Just like the the brine-shrimp have everything they need to start living except water, a coded object saved on disk has all the data needed to recreate itself once initialized with the coder.

典型的例子是 nib 文件.一个 nib 文件只是一堆 UI 元素和控制器的冻干实例.nib 中的 UIViewController 及其 UIView 将初始化自身所需的所有数据编码到 nib 文件的 xml 中.当您直接或使用 IBOutlet 调用 initFromNib 时,它会调用每个类的 intiWithCoder: 方法.

The canonical example of this is a nib file. A nib file is just a bunch of freeze dried instances of UI elements and controllers. A UIViewController and its UIViews in a nib have all the data they need to initialize themselves coded into the xml of the nib file. When you call initFromNib directly or with an IBOutlet, it calls each class' intiWithCoder: method.

如果在冻干对象时没有保存完整的对象,那么实例对象的存在就不需要没有被冻干的属性.

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

You just set those ancillary attributes after the object has been initialized.

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

To inline the designated initializer, you just decode first and then call the designated initializer. Like so:

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

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

If the super class does not support NSCoder then you start it yourself in the subclass:

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

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

That's the simplest case. If super itself supports NSCoding, then you usually just end up writing a parallel designated initializer like so:

- (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 最终会成为并行指定初始化程序,因为它会像指定初始化程序一样处理所有初始化.它看起来不像指定的初始化器,因为它的所有数据都由编码器提供,但它执行相同的功能.

I think in most cases, initWithCoder ends up being a parallel designated initializer because it takes care of all initialization just like the designated initializer should. It doesn't look like the designated initializer because all its data is provided by the coder but it performs the same function.

这是理论和实践不一致的案例之一.指定初始化程序"概念实际上只适用于您从头开始创建实例的情况.

This is one of those cases where theory and practice don't line up well. The "designated initializer" concept really only applies to cases wherein you create instances from scratch.

这篇关于iPhone - initWithCoder 是通常指定初始化程序设计模式的例外吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆