web-dev-qa-db-ja.com

NSKeyedArchiverはSwift 3(XCode 8)では機能しません

プロジェクトを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では整数にキャストしません

16
Arthur Shkil

これは、Swift 2のNSKeyedArchiverでアーカイブされたNSDatablobがSwift 3のNSKeyedUnarchiverで開かれた場合に、Swift 2からSwift 3の更新境界でのみ発生するようです。 。私の推測では、Swift 2では、BoolIntNSNumberとしてエンコードされますが、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")
16
James Kuang

更新:decodeObject(forKey key:String)の代わりにdecodeInteger(forKey key:String)を使用して、この問題を解決しました。何らかの理由で、AnyObjectはSwift 2.2ではキャストしましたが、Swift 3では整数にキャストしません

7
Arthur Shkil

これが解決策です:

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がuserDefaultsからカスタムオブジェクトを保存および取得

3
Amit Soni

Swift 3

二重疑問符?? )メソッドを採用し、1行だけでチャームのように機能します

Valがnilでない場合は、ラップが解除されて値が返されます。 nilの場合、aDecoder.decodeInteger(forKey: "val")が返されます。

self.val = aDecoder.decodeObject(forKey: "val") as? Int ?? aDecoder.decodeInteger(forKey: "val")
1