Cocoa touch NSKeyedArchiver unarchiveObjectWithFile因EXC\u BAD\u指令而崩溃

Cocoa touch NSKeyedArchiver unarchiveObjectWithFile因EXC\u BAD\u指令而崩溃,cocoa-touch,swift,nscoding,nskeyedunarchiver,Cocoa Touch,Swift,Nscoding,Nskeyedunarchiver,我有以下代码,用于获取已存档对象的路径 let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true) let path = paths[0] as String let archivePath = path.stringByAppendingString("archivePath") 当我运

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

let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let path = paths[0] as String
let archivePath = path.stringByAppendingString("archivePath")
当我运行这段代码时,它在
NSSearchPathForDirectoriesInDomains
调用时崩溃,lldb显示

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
在Xcode的Variables视图中,我看到了预期的路径字符串集。在Swift中获取用户目录用于归档/取消归档对象的正确方法是什么

更新

看来这实际上是在破坏我对NSKeyedUnachiver的使用:

stopwatches = NSKeyedUnarchiver.unarchiveObjectWithFile(archivePath) as Stopwatch []
Stopwatch是一个实现NSCoding的类,stopwatches是执行非归档的视图拥有的数据源(一个秒表数组)

更新2

正在存档的对象图是一组秒表。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()
}
更新3: 当
expandTilde
设置为true时,我的路径是
/Users/Justin/Library/Developer/CoreSimulator/Devices/FF808CCD-709F-408D-9416-E‌​E47B306309D/数据/容器/数据/应用程序/B39CCB84-F335-4B70-B732-5C3C26B4F6AC‌​/文档/归档路径

如果我将
expandTilde
设置为false,则不会发生崩溃,但该文件没有存档和未存档,路径为
@“~/Documents/ArchivePath”


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

我遇到了类似的问题,这与Swift的名称损坏有关。如果您正在读取由编码的Objective-C对象生成的文件,并且每个对象都有Objective-C类名
秒表
,则无法将其直接解码为Swift对象,因为Swift会对类和符号名执行名称篡改。您在Swift代码中看到的
Stopwatch
在内部类似于
T23323234\u Stopwatch\u 3242

为了避免这种情况,请指定您的Swift类应使用特定的Objective-C类名称导出,例如:

@objc(Stopwatch) class Stopwatch {
  ...
}
其中
Stopwatch
与您归档的Objective-C对象的类名匹配

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


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

在我的iOS模拟器中工作没有问题。但是stringByAppendingString()应该是pathByAppendingPathComponent()@MartinR更新了新信息你能告诉我们传递的是什么吗?@JackWu当我使用println时它是
/Users/Justin/Library/Developer/CoreSimulator/Devices/FF808CCD-709F-408D-9416-EE47B306309D/data/Containers/data/Application/B39CCB84-F335-4B70-B732-5C3C26B4F6AC/Documents/archivePath
,但是如果我尝试使用lldb打印描述,我会得到
打印ArchivePath的描述:(String)ArchivePath=
有趣,当您归档它时,它是从
秒表[]
变量归档的吗?或者它是一个
NSArray
?这个项目完全是用Swift编写的,从来没有Objective-C对象被编码或解码,有趣的想法你能发布任何或所有的秒表源代码吗?当然-出于好奇,你试着给它起一个objc名称吗?当我使用@objc(秒表)类秒表时。。。(使用未编译的引号),我得到“无法解码类的对象(_whateverStopwatch)。同样,在Beta 3中,失败现在出现在aCoder.encodeObject(self.laps,forKey:“laps”)上,但它是相同的EXC_BAD_指令
let encodedLaps = self.laps.map { lap => ["start": lap.start, "end": lap.end] }
aCoder.encodeObject(encodedLaps, forKey: "laps")