NSKeyedArchiver归档数据时崩溃

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NSKeyedArchiver归档数据时崩溃相关的知识,希望对你有一定的参考价值。

我的应用程序使用以下函数来序列化一组自定义对象(仅显示相关代码):

class func serializeShoppingLocations(buyLocations: Set<ShoppingLocation>) -> Data {
    #if os(ios)
        NSKeyedArchiver.setClassName("ShoppingLocation", for: ShoppingListIOS.ShoppingLocation.self)
    #elseif os(watchOS)
        NSKeyedArchiver.setClassName("ShoppingLocation", for: ShoppingListWatch.ShoppingLocation.self)
    #endif  
    let data = NSKeyedArchiver.archivedData(withRootObject: buyLocations)
    return data
}  

需要iOS和watchOS目标的条件编译,以便允许两个目标稍后解压缩序列化数据,即使它们已被其他目标归档。

ShoppingLocation采用NSCoding协议,并继承自NSObject

这段代码在let data = …指令与EXC_BAD_ACCESS (code=1, address=0x0)崩溃。

我知道错误可能表明引用了一个不存在的对象。但是,变量buyLocations是存在的,我可以在调试器中打印该值,包括集合中对象的所有值。

堆栈跟踪是: enter image description here

堆栈跟踪指示归档程序开始归档NSSet,并尝试归档该组的一个元素,但内部可变字典中的setObjectForKey失败。

可能是什么原因?

编辑:

在进一步测试期间,我意识到当应用程序的至少2个线程处于活动状态时,崩溃总是发生。 特别是,我发现一个线程在一个不同于上面提到的指令时崩溃(Xcode中为红色)的情况:

let dataBlob = NSKeyedArchiver.archivedData(withRootObject: shoppingItem.buyLocations)  

并且另一个线程在上面提到的指令处停止(Xcode中为绿色):

let data = NSKeyedArchiver.archivedData(withRootObject: buyLocations)

可能是NSKeyedArchiver不是线程安全的吗?

答案

我怀疑的问题确实是由多个线程的非同步访问引起的:

一个NSArchiver遍历一个对象图,从根对象开始,并在它遇到的每个对象的路上存档。 因此,为了创建正确的存档,需要在存档器终止之前不改变对象图。

在单线程应用程序中,这是自动保证的。 在一个多线程应用程序中,多个线程可以改变对象图,程序员负责确保这一点,因为归档程序无法阻止其他线程改变根对象。 (例如,如果归档器首先制作对象图的深层副本,然后归档副本,则在深拷贝期间可以突变对象图)。

因此,需要序列化对象图的所有获取和设置访问,例如,通过在串行访问队列中执行它们。

以上是关于NSKeyedArchiver归档数据时崩溃的主要内容,如果未能解决你的问题,请参考以下文章

IOS 数据存储(NSKeyedArchiver 归档篇)

IOS数据持久化之归档NSKeyedArchiver

iOS开发 - 数据归档与恢复 NSKeyedArchiver

用NSKeyedArchiver存储数据(归档)

iOS数据持久化存储之归档NSKeyedArchiver

NSKeyedArchiver