NSAserDefaults和NSArray中自定义对象的条件编码

时间:2011-05-15 13:57:54

标签: iphone objective-c nsmutablearray nsuserdefaults

我知道有很多关于如何在NSArray或NSMutableArray中存档自定义对象并将它们保存在NSUserDefaults中的问题。符合NSCoding协议并保存到NSUserDefaults是没有问题的,我使用NSUserDefaults将很多用户提交的数据存储在我的应用程序中 - 它主要包含代表Person的对象(让我们调用NSObject子类“Person”)具有存储在NSMutableArray中的NSObject子类“Property”的多个对象。因此,数据结构如下所示:

NSMutableArray "persons":
    Person "aPerson":
        NSMutableArray "properties":
            Property "aProperty"
            Property "anotherProperty"
    Person "anotherPerson:
        ...

归档和恢复信息起初并不成问题,因为人员和财产都符合NSCoding协议 - 但现在出现了一个问题,尽管过去几天有数千个谷歌请求,但我还是无法解决这个问题。 )

某些Property对象包含对其他人的引用(“Participants”,它们链接到同一属性并包含在NSMutableArray中)。 当我使用NSKeyedArchiver将整个数据存储到NSUserDefaults时,我使用

[aCoder encodeObject:participants forKey:@"participants"];

在Property的“encodeWithCoder”方法中归档NSMutableArray“参与者”,它存储对其他Person对象的引用。但是当我解码那些Person对象时,它们被创建为new并与已经存在于其他地方的Person对象分开。 NSMutableArray“参与者”只包含引用,指向Person对象的弱链接,因此条件编码其内容,因为可以在“encodeWithCoder”中手动处理其他对象:

[aCoder encodeConditionalObject:anObject forKey:aKey];

当NSMutableArray被解码时,它应该表示对已经存在的Person对象的引用列表 - 而不是全新的对象!测试“aPerson == [[aDecoder decodeObjectForKey:@”participant“] objectAtIndex:0]”当前返回NO,尽管在编码/解码过程发生之前它已经返回YES。

我希望我的解释在某种程度上是可以理解的,你可以帮助我解决我的问题:)简单来说:我如何条件编码NSMutableArray中包含的自定义对象?

谢谢!

2 个答案:

答案 0 :(得分:1)

如果NSMutableArray对其包含的对象使用encodeConditionalObject:forKey:,则只是意味着这些对象根本没有编码,如果它们没有在对象图中的其他位置无条件编码。在这种情况下,这对你没有帮助(数组只是空的)。

问题是你无法真正编码对内存中对象的引用。对象引用基本上只是指向内存中地址的指针。当您下次启动应用程序并创建完全相同的对象(无论是通过取消归档还是其他方式)时,它几乎肯定会在内存中具有不同的地址。 unarchiver无法“神奇地”知道哪个现有对象对应于它已归档的引用,因为当您退出应用程序时,内存地址(对象的“身份”)将失去其所有含义。

您必须使用其他方法来识别对象,例如数据库行ID,字典键等,并手动建立存档密钥与该密钥对应的现有对象的连接。

答案 1 :(得分:0)

我也有这个问题。我有一些对象具有一系列弱链接到其他对象。我知道链接到的所有对象都将被编码,所以我只想确保我可以重建链接。

使用单个弱链接可以使用:

aCoder.encodeConditionalObject(thing, forKey: "Thing")

...如果该项目已经从其他地方编码过,那么将使用对该编码项目的引用。

但是,如果你有一个充满'条件'的数组怎么办?数组需要无条件编码的项目?

我最终包装了我要链接的项目。

class thingLink: NSObject, NSCoding
{
    weak var thing: Thing?

    init(_ thing: Thing) {
        self.thing = thing
    }

    required init?(coder aDecoder: NSCoder) {
        thing = aDecoder.decodeObject(forKey: "Thing") as? Thing
    }

    func encode(with aCoder: NSCoder) {
        // We encode these conditionally as they must be used elsewhere
        aCoder.encodeConditionalObject(thing, forKey: "Thing")
    }
}

...然后我将这些存储在我正常编码的数组中。

aCoder.encode(things, forKey: "Things")

如果我移动到数据库来存储东西,我认为这也会有帮助,因为我需要一个单独的表来存储链接并保持优先级等。