NSCoder 和/或 NSKeyedUnarchiver 如何处理同一对象的多次解码?
我想知道 NSCoder 如何在下次解码时处理由多个对象共享和编码的对象。它会制作该对象的两个副本,还是会解码一个对象并在解码该对象的所有其他对象之间共享?
我在下面提供了一个类似情况的小例子。
示例:
- 应用程序启动
- 对象 A,对象 B 将对象 C 设置为其委托 应用
- 程序收到终止通知。
- 对象 A 和对象 B 对自身及其所有对象(包括其委托)编码
- 应用程序关闭并重新启动
- 对象 A 和对象 B 对自身及其所有对象(包括其委托)解码他们的代表)
在第 6 步之后,对象 A 和对象 B 是否会共享相同的解码对象,或者它们各自都有自己的副本?
I was wondering how NSCoder
would handle an object that was shared and encoded by multiple objects the next time it was decoded. Will it make two copies of the object, or will one object be decoded and shared between all other objects that decode it?
I've provided a small example of a situation like this below.
Example:
- Application starts up
- Object A and Object B set Object C as their delegate
- Application receives termination notification.
- Object A and Object B encode themselves and all of their objects (including their delegates)
- Application shuts down and restarts
- Object A and Object B decode themselves and all of their objects (including their delegates)
Would Object A and Object B both share the same decoded object after step 6 or would they each have their own copy of it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
他们将共享对同一对象的引用(除非您竭尽全力改变该行为)。
即NSCoding可以处理完全循环、全向、复杂连接的对象图(只要所有图参与者正确支持NSCoding)。
请注意,对委托进行编码是非常不典型的。委托通常在归档后连接到未归档的对象图,并且委托充当存档模型层(或存档视图层,在 IB 的情况下)之间的某种管道 - 故事更复杂,真的,对于 XIB 文件...但是...足够接近)以及应用程序的其余部分。
They'll share a reference to the same object (unless you go to lengths to change that behavior).
I.e. NSCoding can deal with fully cyclic, omni-directional, complexly connected, object graphs (as long as all graph participants correctly support NSCoding).
Note that encoding delegates is highly atypical. Delegates are usually connected to an unarchived object graph after anarchival and delegates act as a sort of conduit between your archived model layer (or archived view layer, in the case of IB -- the story is more complex, really, for XIB files... but... close enough) and the rest of your app.
这是一个很好的问题,我自己也一直想知道。于是,我写了一个小测试程序来尝试一下。四个类:
ClassA
、ClassB
、ClassC
和MyBaseClass
。ClassA
、ClassB
和ClassC
继承自MyBaseClass
,它符合NSCoding
并提供两个属性:name
和age
。 A、B 和 C 类是相同的,只是ClassA
和ClassB
还包含对ClassC
实例的引用。ClassA
和ClassB
还重写initwithCoder:
和encodeWithCoder:
以解码和编码它们对C 类
。顶层代码如下所示:对象完美地序列化和反序列化。此外,反序列化后,
ac
和bc
指向ClassC
的同一个实例——也就是说,它们的对象指针具有相同的地址。显然,在
NSKeyedArchiver
的encodeObject:forKey:
中,进行了测试以查看正在编码的对象是否isEqualTo:
先前编码的对象,如果是,则存储引用而不是完整的对象。相反的情况必须发生在NSKeyedUnarchiver
的decodeObject:forKey:
中。非常酷!This is a great question, and I always wondered about it myself. So, I wrote a small test program to try it out. Four classes:
ClassA
,ClassB
,ClassC
, andMyBaseClass
.ClassA
,ClassB
, andClassC
inherit fromMyBaseClass
which conforms toNSCoding
and provides two properties:name
andage
. The A, B, and C classes are identical except thatClassA
andClassB
also contain a reference to an instance ofClassC
.ClassA
andClassB
also overrideinitwithCoder:
andencodeWithCoder:
to decode and encode their references to the instance ofClassC
. Here is what the top-level code looks like:The objects serialize and deserialize perfectly. Also, after deserializing,
a.c
andb.c
point to the same instance ofClassC
— that is, their object pointers have the same address.Apparently, within
NSKeyedArchiver
'sencodeObject:forKey:
, a test is done to see if the object being encodedisEqualTo:
a previously encoded object, and if it is, a reference is stored instead of a complete object. The converse must happen inNSKeyedUnarchiver
'sdecodeObject:forKey:
. Very cool!我认为第一个答案并不完全正确。根据Apple的文档,“序列化仅保留对象的值及其在层次结构中的位置。对同一值对象的多个引用可能会在反序列化时产生多个对象”。
因此,不能保证序列化的单个对象在从多个 NSCoder 反序列化时会生成单个对象。
如果您的实现与您的示例类似,那么您可能没有完全正确地思考事情。如果您考虑应用程序的逻辑组织,多个对象可以共享同一个委托可能是有意义的。但通常我不希望有人使用 NSCoder 协议来编码/解码委托。通常,我希望委托对其作为委托的对象进行编码/解码。
例如,让我们看一下 NSTableView。也许用户能够配置 NSTableView 的显示方式(也许允许用户调整列大小或选择显示哪些列)。这是您可能想要使用 NSCoding 协议保存和恢复的有用信息。 NSTableView 也有代表。委托应该是一个控制器(来自 MVC 范例),并且永远不需要使用 NSCoding 进行编码/解码,因为它是不需要维护任何运行时状态的通用代码。
因此,理想情况下,您使用 init 方法创建委托/控制器。它意识到需要配置 NSTableView 以使其看起来像用户上次配置它时的样子,因此它使用 NSCoding 从磁盘中提取旧的表视图,然后将其显示给用户,就像他们上次看到它一样。
我认为 MVC 范式中的模型层也是如此。同样,控制器层应该解码特定于用户通过使用应用程序所做的事情的模型对象。
听起来更像是您正在尝试从模型或视图层实例化控制器层。这确实没有意义。
I don't think the first answer is entirely correct. According to Apple's documentation, "The serialization only preserves the values of the objects and their position in the hierarchy. Multiple references to the same value object might result in multiple objects when deserialized".
So it's not guaranteed that a single object serialized will result in a single object when deserialized from those multiple NSCoders.
If you're implementation is anything like your example then you may not be thinking about things quite right. If you think about the logical organization of an application it might make sense that multiple objects could share the same delegate. But generally I wouldn't expect somebody to use the NSCoder protocol to encode/decode delegates. Normally I would expect the delegate to encode/decode the objects for which it is the delegate.
For instance let's look at NSTableView. Perhaps the user gets the ability to configure how the NSTableView is displayed (perhaps the user is allowed to resize columns or choose which columns are displayed). This is useful information that you might want to save and restore using the NSCoding protocol. NSTableView's also have delegates. The delegate should be a controller (from the MVC paradigm) and should never really need to be encoded/decoded using NSCoding because it is generic code that does not have to maintain any runtime state.
So Ideally you create your delegate/controller using an init method. It realizes it needs to configure a NSTableView to look the way it did the last time the user configured it, so it pulls an old table view from disk using NSCoding and then displays that to the user just as it was the last time they saw it.
I think the same goes for the Model layer in the MVC Paradigm. Again, the Controller layer should be decoding the model objects which are specific to what the user has done through their use of the application.
It sounds more like you are trying to instantiate the controller layer from the model or perhaps view layer. It doesn't really make sense.