プロジェクトをSwift 3に移行しましたが、NSKeyedArchiver
が機能しません。次のようなオブジェクトをデコードしようとすると、実際にランタイムエラーが発生します。
_let startDayTime = aDecoder.decodeObject(forKey: Key.startDayTime) as! Int
_
Xcode7.3のSwift 2.2)で完全に機能しました。他の誰かがそのような問題に直面したことがありますか?
P.S.シミュレータとデバイスの両方でこのエラーが発生します。
更新:decodeInteger(forKey key: String)
の代わりにdecodeObject(forKey key: String)
を使用してこの問題を解決しました。何らかの理由で、AnyObjectはSwift 2.2ではキャストしましたが、Swift 3では整数にキャストしません
これは、Swift 2のNSKeyedArchiver
でアーカイブされたNSDatablobがSwift 3のNSKeyedUnarchiver
で開かれた場合に、Swift 2からSwift 3の更新境界でのみ発生するようです。 。私の推測では、Swift 2では、Bool
とInt
はNSNumber
としてエンコードされますが、Swift 3では、生のBool
タイプとInt
タイプとしてエンコードされます。次のテストがこの主張を裏付けていると思います。
これはSwift 3で機能し、Swift 2でエンコードされたBool
をアーカイブ解除しますが、BoolがSwift 3でエンコードされた場合はnil
を返します:
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool
これはSwift 3で機能し、Swift 3でエンコードされたBool
をアーカイブ解除しますが、BoolがSwift 2でエンコードされた場合はクラッシュします:
let visible = aDecoder.decodeBool(forKey: "visible")
私の解決策は次のとおりです。
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool ?? aDecoder.decodeBool(forKey: "visible")
更新:decodeObject(forKey key:String)の代わりにdecodeInteger(forKey key:String)を使用して、この問題を解決しました。何らかの理由で、AnyObjectはSwift 2.2ではキャストしましたが、Swift 3では整数にキャストしません
これが解決策です:
class Person: NSObject, NSCoding {
let name: String
let age: Int
required init(name: String, age: Int) {
self.name = name
self.age = age
}
required init(coder decoder: NSCoder) {
self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
self.age = decoder.decodeInteger(forKey: "age")
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: "name")
coder.encode(age, forKey: "age")
}}
使い方:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let newPerson = Person(name: "Joe", age: 10)
var people = [Person]()
people.append(newPerson)
let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
UserDefaults.standard().set(encodedData, forKey: "people")
if let data = UserDefaults.standard().data(forKey: "people"),
myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Person] {
myPeopleList.forEach({print( $0.name, $0.age)}) // Joe 10
} else {
print("There is an issue")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}}
Swift 3:
二重疑問符( ?? )メソッドを採用し、1行だけでチャームのように機能します。
Valがnilでない場合は、ラップが解除されて値が返されます。 nilの場合、aDecoder.decodeInteger(forKey: "val")
が返されます。
self.val = aDecoder.decodeObject(forKey: "val") as? Int ?? aDecoder.decodeInteger(forKey: "val")