2016-06-30 61 views
15

Ho migrato il mio progetto a Swift 3 e NSKeyedArchiver non funziona. Mi hanno fatto un errore di runtime quando si cerca di decodificare oggetto come questo:NSKeyedArchiver non funziona in Swift 3 (XCode 8)

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

ha funzionato perfettamente a Swift 2.2 in Xcode 7.3. Qualcun altro ha affrontato tali problemi?

P.S. Ho questo errore su entrambi Simulator e Device.

AGGIORNAMENTO: Ho risolto questo problema utilizzando decodeInteger(forKey key: String) anziché decodeObject(forKey key: String). Per qualche motivo AnyObject non esegue il cast di Integer in Swift 3 anche se lo ha fatto in Swift 2.2

+0

invitiamo ad aggiungere output degli errori. – yennsarah

+2

Potrebbe essere che l'oggetto era 'nil' o che il cast su' Int' non è riuscito. Dovresti guardare il risultato di 'decodeObject' prima del casting forzato e vedere quale è il problema. Inoltre, per quanto riguarda i numeri interi, puoi usare 'decodeInteger (forKey:)'. – Rob

+0

È necessario aggiungere una soluzione come risposta –

risposta

16

Sembra che ciò avvenga solo sul confine di aggiornamento da Swift 2 a Swift 3 quando un BLOB NSData archiviato con uno NSKeyedArchiver in Swift 2 viene aperto con un NSKeyedUnarchiver a Swift 3. mia ipotesi è che su Swift 2, il Bool e Int sono codificati come NSNumber, ma in Swift 3, sono codificati come prime Bool e Int tipi. Credo che la seguente prova sostiene questa affermazione:

Questo funziona in Swift 3 a decomprimere un Bool codificato in Swift 2, ma restituisce nil se il Bool è stato codificato a Swift 3:

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

Questo funziona in Swift 3 a decomprimere un Bool codificato in Swift 3, ma si blocca se il Bool è stato codificato nel Swift 2:

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

la mia soluzione è:

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

grazie, questo ha funzionato per me. un errore così sottile, hanno davvero bisogno di documentare cose come questa e di risparmiare tempo. – Ryan

+0

Questa dovrebbe essere la risposta migliore perché consente ai clienti di aggiornare in modo sicuro le app che eseguono da 2 a 3 rapide. – pbush25

7

AGGIORNAMENTO: Ho risolto questo problema utilizzando decodeInteger (chiave forKey: String) invece di decodeObject (chiave forKey: String). Per qualche motivo AnyObject non esegue il cast di Integer in Swift 3 anche se lo ha fatto in Swift 2.2

+0

Vuoi menzionare lo stesso per Bool. –

+0

Ho ancora problemi con l'aggiornamento da encodeObject (swift 2), decodeInteger (swift 3) continua a bloccare la mia app :( – George

+0

Ho appena trovato questo post. Ora sto affrontando un problema un po 'simile qui: http: // stackoverflow .com/questions/41224991/nskeyedarchiver-nskeyedunarchiver-swift-3-0 .Spessi anche tu usando NSKeyedUnarchiver. – Michel

1

Swift 3:

adotto il marchio duplice domanda (??) metodo e funziona come un fascino in una sola linea.

Se val non è nullo di quanto non viene scartato e il valore restituito. Se è pari a zero allora aDecoder.decodeInteger(forKey: "val") tornato:

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

Ecco la soluzione:

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

Come usare:

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

Riferimento: Swift 3 saving and retrieving custom object from userDefaults

Problemi correlati