【问题标题】:Pointers to existing objects after encodeWithCoder: and initWithCoder:在 encodeWithCoder: 和 initWithCoder: 之后指向现有对象的指针:
【发布时间】:2018-07-06 21:43:58
【问题描述】:

NSCoding 如何处理指向其他对象而不是值的指针的编码和解码?我有一系列需要编码的模型类,它们需要用弱属性相互引用。我惊讶地发现,在编码、保存到文件、然后从文件中读取并解码后,这些引用似乎得到了维护。即使相互引用的对象的内存地址发生了变化,这仍然有效。我很想知道 NSCoding 是如何实现这一点的,并且还想确保它能够始终如一地工作。

简而言之:如果我对包含指向其他对象的指针的属性进行编码,我是否可以 100% 依赖解码后维护的引用?

【问题讨论】:

    标签: ios objective-c cocoa nscoding nscoder


    【解决方案1】:

    tl;dr: 是的,NSKeyedArchiver 和 NSKeyedUnarchiver 维护对象图中对象的引用关系;如果您对对象引用其他对象的对象图进行编码,则可以期望该图以维护这些关系的方式进行解码。编码和解码后不一定会返回相同的指针,但对象的身份将保持不变。


    当您通过-encodeObject:forKey: 对对象进行编码时,NSKeyedArchiver 永远不会写出对象的指针地址。相反,它维护了一个以前见过的唯一对象表:

    1. 如果您正在编码的对象以前从未见过,则会将其添加到表中并分配一个 UID。然后它调用了-encodeWithCoder:,这样它就可以对其所有属性进行编码
    2. 如果它之前被看到过(并且已经被分配了一个 UID),那么什么都不会发生(但 UID 会记录在它的位置)

    归档完成后,归档包含唯一的对象表,以及另一个表示对象图结构的字典。代替对象的是 UID。

    解码时,当你调用-decodeObject:forKey:时,NSKeyedUnarchiver会做相反的映射:

    1. 它在存档中查找键的 UID,并在唯一表中搜索 UID。如果该对象之前已解码,则返回对解码对象的引用。这是关键部分——您不一定会在解码时获得与在 encode 上编码的相同的 pointer,但您将获得对相同 object 的引用而不是一份副本
    2. 如果之前从未解码过 UID,它会在与 UID 对应的唯一表中查找编码对象,查找类并在对象上调用 +alloc、-initWithCoder: 和 -awakeAfterUsingCoder。然后将该对象记录在 UID 到对象映射中,以便在必要时重复使用

    这是密钥归档系统的主要功能之一,您可以依赖此行为得到维护。

    【讨论】:

    • 感谢您的精彩解释。这是完全有道理的,我确信我现在可以依靠它。我对 Cocoa 和 Objective-C 了解得越多,我就越喜欢它。我已经为 iOS 开发应用程序 8 年了,我还在学习:)
    • @mashers 太棒了! :) 很高兴能提供帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    • 2014-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多