Swift中應該如何處理與NSCoding相關的錯誤?處理Swift中的NSCoding錯誤
當使用init?(coder:)
對對象進行初始化時,如果數據無效,則可能無法初始化對象。我想抓住這些錯誤並妥善處理它們。爲什麼init?(coder:)
沒有在Swift中定義爲拋出函數?
Swift中應該如何處理與NSCoding相關的錯誤?處理Swift中的NSCoding錯誤
當使用init?(coder:)
對對象進行初始化時,如果數據無效,則可能無法初始化對象。我想抓住這些錯誤並妥善處理它們。爲什麼init?(coder:)
沒有在Swift中定義爲拋出函數?
NSCoding
將其定義爲可選:
init?(coder aDecoder: NSCoder)
所以它肯定是可以檢測的錯誤。
90%的「爲什麼Swift ...?」問題可以用「因爲可可」來解答。可可並沒有將initWithCoder:
定義爲返回一個錯誤,所以它不會在Swift中轉換爲throws
。沒有辦法將它與現有代碼完美地結合在一起。 (NSCoding
追溯到NeXTSTEP的,因爲我們已經有很多軟件不返回NSError
那裏。這並不意味着它可能不是很好的時候,但是「無法初始化」已經夠傳統)
檢查nil
。這意味着某些失敗。這是提供的所有信息。
我從來沒有在實踐中必須檢查太深,整個對象圖是正確的。如果不是,那麼你很可能會得到其他錯誤,並且記住NSKeyedUnarchiver
如果解碼失敗將會引發一個ObjC異常(!!!)。除非你將它包裝在ObjC @catch
中,否則無論如何你都會崩潰。 (是的,這是非常瘋狂的,但仍然如此。)
但是,如果我想非常小心,並確保我期望在檔案中的東西真的在檔案中(即使它們是nil
),我可能會做這種方式(未經測試,它編譯,但我還沒有確定它確實有效):
import Foundation
enum DecodeError: ErrorType {
case MissingProperty(String)
case MalformedProperty(String)
}
extension NSCoder {
func encodeOptionalObject(obj: AnyObject?, forKey key: String) {
let data = obj.map{ NSKeyedArchiver.archivedDataWithRootObject($0) } ?? NSData()
self.encodeObject(data, forKey: key)
}
func decodeRequiredOptionalObjectForKey(key: String) throws -> AnyObject? {
guard let any = self.decodeObjectForKey(key) else {
throw DecodeError.MissingProperty(key)
}
guard let data = any as? NSData else {
throw DecodeError.MalformedProperty(key)
}
if data.length == 0 {
return nil // Found nil
}
// But remember, this will raise an ObjC exception if it's malformed data!
guard let prop = NSKeyedUnarchiver.unarchiveObjectWithData(data) else {
throw DecodeError.MalformedProperty(key)
}
return prop
}
}
class MyClass: NSObject, NSCoding {
static let propertyKey = "property"
let property: String?
init(property: String?) {
self.property = property
}
required init?(coder aDecoder: NSCoder) {
do {
property = try aDecoder.decodeRequiredOptionalObjectForKey(MyClass.propertyKey) as? String
} catch {
// do something with error if you want
property = nil
super.init()
return nil
}
super.init()
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeOptionalObject(property, forKey: MyClass.propertyKey)
}
}
正如我所說的,在可可節目,我從來沒有真正做到了這一點。如果存檔中的任何內容真的損壞了,那麼幾乎肯定會結束引發ObjC異常的情況,所以所有這些錯誤檢查都可能是過度的。但它確實可以讓你區分「無」和「不在檔案中」。我只是編碼屬性單獨作爲NSData
,然後編碼NSData
。如果它是nil
,我編碼一個空的NSData
。
這很有道理。你的觀點是,它建立在現有的可可行爲上是完全有效的。我認爲這可能是我對「NSCoding」理解的一個問題。在Objective-C中做類似的事情我已經在try/catch塊中包裝了一些複雜圖形的頂級對象,但是這裏的錯誤實際上必須是我將nil值分配給非可選屬性,在初始化時解碼如果任何值爲零,整個初始化器應該返回nil。這聽起來正確嗎? –
正確。你需要返回nil(這也意味着,今天不幸)你必須找到* some *的方式來初始化所有的屬性。你必須在返回nil之前初始化所有的東西,而Swift團隊承認的東西有點壞。 –
明白了。我還沒有消化failable initializers,但我可以學習。你有沒有處理有效的零值的建議?例如:在類型A的存檔對象中有一個類型爲B的可選屬性。如果類型B的實例不能被初始化,它的'init?(coder:)'返回nil。對象A將使用'nil'初始化它的屬性並處於有效狀態。我寧願讓對象A仍然失敗,因爲如果圖中的任何屬性都失敗了,它就沒有意義了。那有意義嗎?在這種情況下有沒有辦法處理? –