iPhone —— initWithCoder 是通常指定初始化器设计模式的例外吗?
我有一个班级MyClass。它有实例变量passedInVar1、passedInVar2等,它们的值将从请求初始化的对象传入。它还具有实例变量decodedVar1、decodedVar2等,这些变量将从存档中解码——或者如果没有存档则设置为默认值。
根据 Apple,
当一个对象接收到 initWithCoder: 消息时,该对象应该首先向其超类(如果适用)发送消息来初始化继承的实例变量,然后应该解码并初始化自己的实例变量实例变量。
但苹果公司还表示,一个类应该有一个指定的初始值设定项。
处理这一切的最好方法是什么?
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.
According to Apple,
When an object receives an initWithCoder: message, the object should first send a message to its superclass (if appropriate) to initialize inherited instance variables, and then it should decode and initialize its own instance variables.
But Apple also says that a class should have a single designated initializer.
What is the best way to deal with all of this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
苹果说:
原则上,指定的初始化程序是所有其他 init 方法调用的一个 init 方法。然而,它并不是唯一的 init 方法。每个类也不必有自己的类。在实践中,更常见的情况是指定的初始化器实际上是超类的 init。
initWithCoder
的主要功能是允许从存档对象进行初始化。对于需要某些特定数据的类,它的指定初始化程序将接受该数据。initWithCoder
然后简单地解压缩存档,然后调用指定的初始化程序。例如,UIView 的指定初始化器是
initWithFrame:
。因此,UIView 的 initWithCoder 看起来像这样:指定初始化器的要点是创建一个所有初始化都必须经过的中心点,以确保每个实例都完全初始化,无论数据来自何处来自或初始化的情况。
这绝不意味着一个类只能有一个初始化方法。
Edit01
来自评论:
好吧,你不知道。 initWithCoder 的全部意义在于,您正在处理类的冷冻干燥实例,其中包含重新创建对象所需的所有数据。
NSCoding 协议使您的类的行为就像漫画书中作为“海猴”出售的丰年虾一样。编码方法对丰年虾/实例进行脱水/冷冻干燥。解码方法使丰年虾/实例水合,就像将丰年虾倒入水中一样。就像丰年虾除了水之外拥有开始生存所需的一切一样,保存在磁盘上的编码对象也拥有一旦用编码器初始化后重新创建自身所需的所有数据。
典型的例子是 nib 文件。 nib 文件只是一堆 UI 元素和控制器的冷冻干燥实例。 nib 中的 UIViewController 及其 UIView 将其初始化所需的所有数据编码到 nib 文件的 xml 中。当您直接调用
initFromNib
或使用 IBOutlet 调用时,它会调用每个类的intiWithCoder:
方法。如果在冻干时不保存完整的对象,则实例对象的存在不需要未冻干的属性。
您只需在对象初始化后设置这些辅助属性即可。
要内联指定的初始值设定项,只需先解码,然后调用指定的初始值设定项。像这样:
如果超类不支持 NSCoder,那么你可以在子类中自己启动它:
这是最简单的情况。如果 super 本身支持 NSCoding,那么您通常最终会编写一个并行指定初始化程序,如下所示:
我认为在大多数情况下,
initWithCoder
最终成为并行指定初始化程序,因为它负责所有初始化,就像指定的初始化程序应该。它看起来不像指定的初始化器,因为它的所有数据都是由编码器提供的,但它执行相同的功能。这是理论与实践不一致的情况之一。 “指定初始化程序”概念实际上仅适用于从头开始创建实例的情况。
Apples says that:
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.
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.For example, the designated initializer for UIView is
initWithFrame:
. So, UIView'sinitWithCoder
looks something like: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.
Edit01
From comments:
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.
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.
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.If you don't save the complete object when you freeze dry it, then the attributes that don't get freeze dried aren't needed for the instance object to exist.
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:
If the super class does not support NSCoder then you start it yourself in the subclass:
That's the simplest case. If super itself supports NSCoding, then you usually just end up writing a parallel designated initializer like so:
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.