NSKeyedArchiver unarchiveObjectWithFile与EXC_BAD_INSTRUCTION崩溃

JuJ*_*oDi 7 cocoa-touch nscoding nskeyedunarchiver swift

我有以下代码,用于获取已归档的对象的路径

let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let path = paths[0] as String
let archivePath = path.stringByAppendingString("archivePath")
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时,它会在NSSearchPathForDirectoriesInDomainslldb显示的调用时崩溃

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Run Code Online (Sandbox Code Playgroud)

在Xcode的变量视图中,我看到路径字符串设置为我所期望的.在Swift中获取用户目录以归档/取消归档对象的正确方法是什么?

更新:

看来这实际上是因为我对NSKeyedUnarchiver的使用而崩溃了:

stopwatches = NSKeyedUnarchiver.unarchiveObjectWithFile(archivePath) as Stopwatch []
Run Code Online (Sandbox Code Playgroud)

Stopwatch是一个实现NSCoding的类,stopwatches是执行unarchiving的视图所拥有的数据源(一组Stopwatches).

更新2:

存档的对象图是Stopwatches数组.NSCoding实现如下:

func encodeWithCoder(aCoder: NSCoder!) {
    aCoder.encodeBool(self.started, forKey: "started")
    aCoder.encodeBool(self.paused, forKey: "paused")
    aCoder.encodeObject(self.startTime, forKey: "startTime")
    aCoder.encodeObject(self.pauseTime, forKey: "pauseTime")
    aCoder.encodeInteger(self.id, forKey: "id")
}

init(coder aDecoder: NSCoder!) {
    self.started = aDecoder.decodeBoolForKey("started")
    self.paused = aDecoder.decodeBoolForKey("paused")
    self.startTime = aDecoder.decodeObjectForKey("startTime") as NSDate
    self.pauseTime = aDecoder.decodeObjectForKey("pauseTime") as NSDate
    self.id = aDecoder.decodeIntegerForKey("id")
    super.init()
}
Run Code Online (Sandbox Code Playgroud)

更新3:expandTilde设置为true我的路径是/Users/Justin/Library/Developer/CoreSimulator/Devices/FF808CCD-709F-408D-9416-E??E47B306309D/data/Containers/Data/Application/B39CCB84-F335-4B70-B732-5C3C26B4F6AC??/Documents/ArchivePath

如果我设置expandTilde为false,我没有得到崩溃,但文件没有存档和取消存档,路径是@"~/Documents/ArchivePath"

删除Application文件夹会导致应用程序的首次启动不会崩溃,但之后不允许它重新打开.此外,删除应用程序文件夹后,我现在能够读取lldb中的存档路径,而不必打印它.

Bil*_*ill 8

我遇到了类似的问题,它与Swift的名字损坏有关.如果您正在读取从编码的Objective-C对象生成的文件,并且每个对象都具有Objective-C类名Stopwatch,那么您将无法直接将其解码为Swift对象,因为Swift在类上执行名称修改符号名称.您Stopwatch在Swift代码中看到的内容就像是T23323234_Stopwatch_3242.

要解决它,请指定应使用特定的Objective-C类名导出Swift类,例如:

@objc(Stopwatch) class Stopwatch {
  ...
}
Run Code Online (Sandbox Code Playgroud)

其中Stopwatch匹配您已归档的Objective-C对象的类名.

编辑:在您在评论中链接的项目代码中,这里存在第二个问题,即尝试编码/解码特定于Swift的功能.只能存档和取消存档Objective-C对象.遗憾的是,结构,泛型,元组和选项不是Objective-C兼容的,不能使用NSCoding.解决此问题的最佳方法是将Swift类型编码为NSDictionary实例,例如(未经测试):

let encodedLaps = self.laps.map { lap => ["start": lap.start, "end": lap.end] }
aCoder.encodeObject(encodedLaps, forKey: "laps")
Run Code Online (Sandbox Code Playgroud)

编辑2:与我上面所写的相反,这不仅限于从Swift中读取Objective-C实例.似乎任何使用都NSCoding需要您的类的Objective-C名称.我想这是因为Swift名称修改可以在编译器的不同运行之间进行更改.