3

我想知道NSCoder下次解码时如何处理由多个对象共享和编码的对象。它会复制该对象的两个副本,还是将一个对象解码并在解码它的所有其他对象之间共享?

我在下面提供了一个类似这种情况的小例子。

例子:

  1. 应用程序启动
  2. 对象 A 和对象 B 将对象 C 设置为它们的委托
  3. 应用程序收到终止通知。
  4. 对象 A 和对象 B对它们自己和它们的所有对象(包括它们的委托)进行编码
  5. 应用程序关闭并重新启动
  6. 对象 A 和对象 B解码自己和它们的所有对象(包括它们的委托)

在第 6 步之后,对象 A 和对象 B 会共享相同的解码对象,还是它们各自拥有自己的副本?

4

3 回答 3

7

它们将共享对同一对象的引用(除非您竭尽全力改变这种行为)。

即 NSCoding 可以处理完全循环、全方位、复杂连接的对象图(只要所有图参与者都正确支持 NSCoding)。

请注意,编码代表是非常不典型的。代理通常在无存档连接到未存档的对象图,并且代理充当存档模型层(或存档视图层,在 IB 的情况下)之间的一种管道——对于 XIB 文件来说,这个故事实际上更复杂。 .但是...足够接近)和您的应用程序的其余部分。

于 2011-09-26T23:58:25.933 回答
5

这是一个很好的问题,我自己也一直想知道。所以,我写了一个小测试程序来尝试一下。四个类别:ClassAClassBClassCMyBaseClassClassA, ClassB, and ClassCinherit from MyBaseClasswhich 符合NSCoding并提供两个属性:nameage。除了这些之外,A、B 和 C 类是相同的,ClassA并且ClassB还包含对 的实例的引用ClassCClassA并且ClassB还覆盖initwithCoder:encodeWithCoder:解码和编码它们对 . 实例的引用ClassC。这是顶级代码的样子:

ClassA *a = [[ClassA alloc] initWithName:@"Mr. A" age:11];
ClassB *b = [[ClassB alloc] initWithName:@"Mrs. B" age:22];
ClassC *c = [[ClassC alloc] initWithName:@"Ms. C" age:33];

b.c = c;
a.c = c;

NSArray *rootObject = @[a, b, c];
NSString *const kFilePath = @"/Users/myname/Documents/testarchive";
BOOL result = [NSKeyedArchiver archiveRootObject:rootObject toFile:kFilePath];
NSLog(@"result = %@", (result) ? @"YES" : @"NO");

NSArray *newRootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:kFilePath];
NSLog(@"new root object = %@", newRootObject);

对象完美地序列化和反序列化。另外,反序列化后,a.cb.c指向同一个实例ClassC——也就是说,它们的对象指针具有相同的地址。

显然,在NSKeyedArchiver'sencodeObject:forKey:中,会进行测试以查看被编码isEqualTo:的对象是否是先前编码的对象,如果是,则存储引用而不是完整的对象。相反的情况必须发生在NSKeyedUnarchiver'sdecodeObject:forKey:中。很酷!

于 2013-10-11T00:11:10.633 回答
0

我不认为第一个答案是完全正确的。根据 Apple 的文档,“序列化仅保留对象的值及其在层次结构中的位置。对同一值对象的多次引用可能会在反序列化时产生多个对象”。

因此,当从多个 NSCoder 反序列化时,不能保证单个对象序列化会产生单个对象。

如果您的实现与您的示例类似,那么您可能没有正确地考虑事情。如果您考虑应用程序的逻辑组织,那么多个对象可以共享同一个委托可能是有意义的。但通常我不希望有人使用 NSCoder 协议来编码/解码委托。通常我希望委托对它作为委托的对象进行编码/解码。

例如,让我们看看 NSTableView。也许用户可以配置 NSTableView 的显示方式(也许用户可以调整列的大小或选择显示哪些列)。这是您可能希望使用 NSCoding 协议保存和恢复的有用信息。NSTableView 也有代表。委托应该是一个控制器(来自 MVC 范例),并且永远不需要使用 NSCoding 进行编码/解码,因为它是不需要维护任何运行时状态的通用代码。

所以理想情况下,您使用 init 方法创建您的委托/控制器。它意识到它需要配置一个 NSTableView 以使其看起来与用户上次配置它时的方式相同,因此它使用 NSCoding 从磁盘中提取一个旧的表视图,然后将其显示给用户,就像他们最后一次看到它一样.

我认为 MVC 范式中的模型层也是如此。同样,控制器层应该解码特定于用户通过使用应用程序所做的模型对象。

这听起来更像是您试图从模型或视图层实例化控制器层。这真的没有意义。

于 2011-09-27T00:05:13.813 回答