wake-up-neo.com

NSKeyedArchiver funktioniert nicht in Swift 3 (XCode 8)

Ich habe mein Projekt nach Swift 3 migriert und NSKeyedArchiver funktioniert nicht. Ich habe tatsächlich einen Laufzeitfehler, wenn ich versuche, ein Objekt wie dieses zu decodieren:

let startDayTime = aDecoder.decodeObject(forKey: Key.startDayTime) as! Int

Es hat in Swift 2.2 in Xcode 7.3 perfekt funktioniert. Hat noch jemand solche Probleme gehabt?

P.S. Ich habe diesen Fehler sowohl im Simulator als auch im Gerät.

UPDATE: Ich habe dieses Problem durch die Verwendung von decodeInteger(forKey key: String) anstelle von decodeObject(forKey key: String) gelöst. Aus irgendeinem Grund wird AnyObject in Swift 3 nicht in Integer umgewandelt, obwohl dies in Swift 2.2 der Fall war

16
Arthur Shkil

Es scheint, dass dies nur an der Aktualisierungsgrenze von Swift 2 nach Swift 3 geschieht, wenn ein mit NSKeyedArchiver in Swift 2 archivierter NSData-Blob mit einem NSKeyedUnarchiver in Swift 3 geöffnet wird. Ich schätze, dass auf Swift 2 , Bool und Int werden als NSNumber codiert, aber in Swift 3 werden sie als rohe Bool - und Int-Typen codiert. Ich glaube, dass der folgende Test diese Behauptung stützt:

Dies funktioniert in Swift 3, um ein in Swift 2 codiertes Bool aufzuheben, gibt jedoch nil zurück, wenn der Bool in Swift 3 codiert wurde:

let visible = aDecoder.decodeObject(forKey: "visible") as? Bool

Dies funktioniert in Swift 3, um ein in Swift 3 codiertes Bool aufzuheben, stürzt jedoch ab, wenn der Bool in Swift 2 codiert wurde:

let visible = aDecoder.decodeBool(forKey: "visible")

Meine Lösung ist:

let visible = aDecoder.decodeObject(forKey: "visible") as? Bool ?? aDecoder.decodeBool(forKey: "visible")
16
James Kuang

UPDATE: Ich habe dieses Problem mit decodeInteger (forKey key: String) anstelle von decodeObject (forKey key: String) gelöst. Aus irgendeinem Grund wird AnyObject in Swift 3 nicht in Integer umgewandelt, obwohl dies in Swift 2.2 der Fall war

7
Arthur Shkil

Hier ist die Lösung:

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")
}}

Wie benutzt man:

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()
}}

Referenz: Swift 3 Benutzerdefiniertes Objekt von userDefaults speichern und abrufen

3
Amit Soni

Swift 3 :

Ich nehme die Methode doppeltes Fragezeichen ( ?? ) an und sie funktioniert wie ein Zauber in nur einer Zeile .

Wenn val nicht gleich Null ist, wird es ausgepackt und der Wert wird zurückgegeben. Wenn es gleich null ist, wurde aDecoder.decodeInteger(forKey: "val") zurückgegeben:

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