ios swift nscoding nskeyedunarchiver

ios - ¿Cómo puedo decodificar un objeto cuando la clase original no está disponible?



swift nscoding (5)

Tengo una aplicación iOS 7 que guarda un objeto personalizado en la carpeta iCloud Docs de la aplicación como un archivo. Para ello, hago uso del protocolo NSCoding.

@interface Person : NSObject <NSCoding> @property (copy, nonatomic) NSString *name @property (copy, nonatomic) NSString *lastName @end

La serialización de objetos funciona perfectamente en la versión iOS 7 de la aplicación:

  1. initWithCoder y encodeWithCoder

  2. [NSKeyedArchiver archivedDataWithRootObject:person]

  3. person = NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)theData]

Pero necesito mover esta aplicación a iOS 8, y esta clase se codificará rápidamente y se "renombrará" para esta nueva versión de la aplicación iOS 8.

class PersonOldVersion: NSObject, NSCoding { var name = "" var lastName = "" }

Cuando intento desarchivar el objeto, recibo el siguiente error:

*** Terminating app due to uncaught exception ''NSInvalidUnarchiveOperationException'', reason: ''*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (Person)''

Ya intenté cambiar el nombre de la clase swift ''PersonOldVersion'' al nombre de la clase original (''Person'') pero aún falla.

¿Cómo puedo decodificar un objeto cuya clase original no está disponible?


Aquí hay una traducción de Swift para la respuesta anterior de Ferran Maylinch.

Tenía un problema similar en un proyecto Swift después de que duplicara el objetivo original para tener 2 versiones de mi producto. Las 2 versiones necesitaban ser intercambiables.

Entonces, tenía algo como myapp_light.app y mi app_pro.app. Configuración de la clase solucionó este problema.

NSKeyedUnarchiver.setClass(MyClass1.classForKeyedUnarchiver(), forClassName: "myapp_light.MyClass1") NSKeyedUnarchiver.setClass(MyClass1.classForKeyedUnarchiver(), forClassName: "myapp_pro.MyClass1") if let object:AnyObject = NSKeyedUnarchiver.unarchiveObjectWithFile("/path/...") { var myobject = object as! Dictionary<String,MyClass1> //-- other stuff here }


Creo que podrías resolverlo de la siguiente manera:

@implementation PersonOldVersion + (void)load { [NSKeyedUnarchiver setClass:[PersonOldVersion class] forClassName:@"Person"]; }


Esta podría ser otra solución, y es lo que hice (ya que no uso Swift).

En mi caso, archivé un objeto de la clase "Ciudad", pero luego cambié el nombre de la clase a "CityLegacy" porque creé una clase "Ciudad" completamente nueva.

Tuve que hacer esto para desarchivar el antiguo objeto "Ciudad" como un objeto "CityLegacy":

// Tell the NSKeyedUnarchiver that the class has been renamed [NSKeyedUnarchiver setClass:[CityLegacy class] forClassName:@"City"]; // Unarchive the object as usual NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSData *data = [defaults objectForKey:@"city"]; CityLegacy *city = [NSKeyedUnarchiver unarchiveObjectWithData:data];


Si el nombre de la clase en Objective-C es importante, debe especificar explícitamente el nombre. De lo contrario, Swift proporcionará algún nombre destrozado.

@objc(Person) class PersonOldVersion: NSObject, NSCoding { var name = "" var lastName = "" }


La respuesta de newacct me ayudó con el nombre de la clase, pero también tuve un problema en el que cambié un nombre de variable en mi clase Swift de mi clase Objective-C. El uso de @objc() solucionó también:

Clase vieja:

@interface JALProgressData : NSObject <NSCoding> @property (nullable, nonatomic, strong) NSString *platformID; @property (nonatomic, assign) NSTimeInterval secondsPlayed; @property (nonatomic, assign) NSTimeInterval totalDuration; @property (nullable, nonatomic, strong) NSDate *lastUpdated; @end

Nueva clase:

@objc(JALProgressData) class VideoProgress: NSObject, NSCoding { @objc(platformID) var videoId: String? var secondsPlayed: NSTimeInterval? var totalDuration: NSTimeInterval? var lastUpdated: NSDate? }

También me di cuenta de que estaba usando encodeObject decodeObjectForKey para tipos de valor, lo que estaba causando problemas con mi clase Swift. El cambio a encodeDouble y decodeDoubleForKey para los tipos aDecoder corrigió un aDecoder devolvía nil para esos valores.