使用可失败初始化程序时崩溃
Crash using failable initializer
我在 Swift 中使用可失败初始化程序时遇到奇怪的崩溃。我很确定这是 Swift 中的错误,但我想我会快速 post 看看我是否遗漏了一些明显的东西。
我正在使用 CloudKit 编写一个应用程序并向 CKRecord 添加了一个新的便利初始化程序:
extension CKRecord {
convenience init?(cloudInfo: NSData?) {
guard let info = cloudInfo else { return nil }
self.init(coder: NSKeyedUnarchiver(forReadingWithData: info))
}
这仅使用我使用 CKRecord 的 encodeSystemFieldsWithCode:
方法创建的存档数据来创建 CKRecord
实例。我以前只是在我的 class 中有一个方法来做同样的事情,而且效果很好。
当我这样调用这个初始化程序时:
let record: CKRecord
if let rec = CKRecord(cloudInfo: self.cloudInfo) {
record = rec
} else {
record = CKRecord(recordType: "Item", recordID: CKRecordID(recordName: self.id))
}
当我拨打那个电话时,我遇到了崩溃。我是否为 cloudInfo
或值传入 nil 并不重要。单步执行代码时,崩溃似乎发生在从 init 调用返回和返回调用者之间。例如,如果我传递 nil
并进入 init
中的 guard
语句,这似乎有效,但一旦我离开它,我就会崩溃。
我尝试摆脱 guard
并使用简单的 if let
构造,但结果相同。而且,我还刚刚从 init
返回了 nil
,没有任何其他代码,这也崩溃了。
我已经完成了常规操作:清理构建文件夹、重新启动等。
顺便说一句,"crash" 我的意思是我在呼叫站点得到:EXC_BAD_ACCESS (code=1, address=0xfffffffc)
。
有人有什么想法吗?也许我缺少的东西很明显。
谢谢。
根据The Swift Programming Language (Swift 2.1)一书,
For classes, however, a failable initializer can trigger an initialization failure only after all stored properties introduced by that class have been set to an initial value and any initializer delegation has taken place.
摘自 here.
您不能使用存储的属性扩展现有的 class,因此满足第一个要求。但是为了满足第二个要求,你必须像下面的代码一样委托你的初始化过程:
extension CKRecord {
convenience init?(cloudInfo: NSData?) {
guard let info = cloudInfo else {
self.init(coder: NSKeyedUnarchiver(forReadingWithData: NSData()))
return nil
}
self.init(coder: NSKeyedUnarchiver(forReadingWithData: info))
}
}
实际上在 Swift 3 中,似乎有一个错误和 Swift 2 的回归:returning nil from a failable intializer crash the runtime.
我在 Swift 中使用可失败初始化程序时遇到奇怪的崩溃。我很确定这是 Swift 中的错误,但我想我会快速 post 看看我是否遗漏了一些明显的东西。
我正在使用 CloudKit 编写一个应用程序并向 CKRecord 添加了一个新的便利初始化程序:
extension CKRecord {
convenience init?(cloudInfo: NSData?) {
guard let info = cloudInfo else { return nil }
self.init(coder: NSKeyedUnarchiver(forReadingWithData: info))
}
这仅使用我使用 CKRecord 的 encodeSystemFieldsWithCode:
方法创建的存档数据来创建 CKRecord
实例。我以前只是在我的 class 中有一个方法来做同样的事情,而且效果很好。
当我这样调用这个初始化程序时:
let record: CKRecord
if let rec = CKRecord(cloudInfo: self.cloudInfo) {
record = rec
} else {
record = CKRecord(recordType: "Item", recordID: CKRecordID(recordName: self.id))
}
当我拨打那个电话时,我遇到了崩溃。我是否为 cloudInfo
或值传入 nil 并不重要。单步执行代码时,崩溃似乎发生在从 init 调用返回和返回调用者之间。例如,如果我传递 nil
并进入 init
中的 guard
语句,这似乎有效,但一旦我离开它,我就会崩溃。
我尝试摆脱 guard
并使用简单的 if let
构造,但结果相同。而且,我还刚刚从 init
返回了 nil
,没有任何其他代码,这也崩溃了。
我已经完成了常规操作:清理构建文件夹、重新启动等。
顺便说一句,"crash" 我的意思是我在呼叫站点得到:EXC_BAD_ACCESS (code=1, address=0xfffffffc)
。
有人有什么想法吗?也许我缺少的东西很明显。
谢谢。
根据The Swift Programming Language (Swift 2.1)一书,
For classes, however, a failable initializer can trigger an initialization failure only after all stored properties introduced by that class have been set to an initial value and any initializer delegation has taken place.
摘自 here.
您不能使用存储的属性扩展现有的 class,因此满足第一个要求。但是为了满足第二个要求,你必须像下面的代码一样委托你的初始化过程:
extension CKRecord {
convenience init?(cloudInfo: NSData?) {
guard let info = cloudInfo else {
self.init(coder: NSKeyedUnarchiver(forReadingWithData: NSData()))
return nil
}
self.init(coder: NSKeyedUnarchiver(forReadingWithData: info))
}
}
实际上在 Swift 3 中,似乎有一个错误和 Swift 2 的回归:returning nil from a failable intializer crash the runtime.