我有以下结构:

struct Identity {
    var id: Int
    var createdAt: NSDate
    var string: String
    var apnsToken: String
}

在我的应用程序执行过程中,实例(?)将此结构的转换为NSData(使用以下代码)并存储在NSUserDefaults中:
var id = Identity(id: 0, createdAt: NSDate(), string: "string", apnsToken: "<apns-token-here>")
var data = NSData(bytesNoCopy: &id, length: sizeof(Identity),freeWhenDone:false)

当我试图从NSData实例获取结构时,它会因EXC_BAD_访问(代码1)而崩溃:
var id = UnsafePointer<Identity>(userDefaultsData.bytes).memory

但是,只有当我从NSUserDefaults获得NSData实例时,才会发生这种情况。如果我做下面这样的事情,它不会崩溃。
var id = Identity(id: 0, createdAt: NSDate(), string: "string", apnsToken: "<apns-token-here>")
var data = NSData(bytesNoCopy: &id, length: sizeof(Identity),freeWhenDone:false)
var idPrime = UnsafePointer<Identity>(data.bytes).memory

EXC_BAD_ACCESS转储的程序集代码位于objc_retain的中途,在and指令之后。
更新:
我不是很诚实。数据从ObjC的keychain中检索,bridge_transfer cast to anNSDatafrom a CF data object。CF对象来自于SecItemCopy()作为out参数。我认为NSUserDefaults会更容易联系。

最佳答案

这是因为这一行:

var data = NSData(bytesNoCopy: &id, length: sizeof(Identity),freeWhenDone:false)

不会将Strings(或分配自己内存的任何其他类型,如数组)呈现为字节形式。相反,它所做的只是将指向字符串内存的指针序列化到NSData字节中。
如果记忆不再存在,这显然会导致爆炸。这就是为什么当你一次完成所有任务时,它看起来是有效的,但当你存储到用户默认值,然后,以后,甚至在另一个过程中,把它取出来的时候,它就不起作用了。
相反,您需要做一些事情,比如将字符串存储到它们自己的NSData对象(比如使用NSData(base64EncodedString:options:))中,然后再存储它。

10-05 21:13
查看更多