J'ai une application iOS 7 qui enregistre un objet personnalisé dans le dossier iCloud Docs de l'application en tant que fichier. Pour cela, j'utilise le protocole NSCoding.
@interface Person : NSObject <NSCoding>
@property (copy, nonatomic) NSString *name
@property (copy, nonatomic) NSString *lastName
@end
La sérialisation d'objets fonctionne parfaitement dans la version iOS 7 de l'application:
initWithCoder
et encodeWithCoder
[NSKeyedArchiver archivedDataWithRootObject:person]
person = NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)theData]
Mais je dois déplacer cette application vers iOS 8, et cette classe sera codée en Swift et "renommée" pour cette nouvelle version iOS 8 de l'application.
class PersonOldVersion: NSObject, NSCoding {
var name = ""
var lastName = ""
}
Lorsque j'essaie de désarchiver l'objet, j'ai eu l'erreur suivante:
*** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (Person)'
J'ai déjà essayé de renommer Swift class 'PersonOldVersion' en nom de classe d'origine ('Person') mais échoue toujours.
Comment puis-je décoder un objet dont la classe d'origine n'est pas disponible?
Si le nom de la classe dans Objective-C est important, vous devez spécifier explicitement le nom. Sinon, Swift fournira un nom déformé.
@objc(Person)
class PersonOldVersion: NSObject, NSCoding {
var name = ""
var lastName = ""
}
Cela pourrait être une autre solution, et c'est ce que j'ai fait (puisque je n'ai pas utilisé Swift à ce moment-là).
Dans mon cas, j'ai archivé un objet de la classe "City" mais j'ai ensuite renommé la classe en "CityLegacy" car j'ai créé une classe "City" complètement nouvelle.
J'ai dû faire cela pour désarchiver l'ancien objet "City" en tant qu'objet "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];
Voici une Swift pour la réponse de Ferran Maylinch ci-dessus.
J'ai eu un problème similaire dans un projet Swift après avoir dupliqué la cible d'origine afin d'avoir 2 versions de mon produit. Les 2 versions devaient être utilisables de manière interchangeable.
Donc, j'avais quelque chose comme myapp_light.app et mon app_pro.app. La définition de la classe a résolu ce problème.
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
}
Je pense que vous pouvez le résoudre comme suit:
@implementation PersonOldVersion
+ (void)load
{
[NSKeyedUnarchiver setClass:[PersonOldVersion class] forClassName:@"Person"];
}
réponse de newacct m'a aidé avec le nom de la classe, mais j'ai également eu un problème où j'ai changé un nom de variable dans ma classe Swift de ma classe Objective-C. Utilisation de @objc()
a corrigé cela aussi:
Ancienne classe:
@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
Nouvelle classe:
@objc(JALProgressData)
class VideoProgress: NSObject, NSCoding {
@objc(platformID) var videoId: String?
var secondsPlayed: NSTimeInterval?
var totalDuration: NSTimeInterval?
var lastUpdated: NSDate?
}
J'ai également réalisé que j'utilisais encodeObject
decodeObjectForKey
pour les types de valeur, ce qui posait des problèmes avec ma Swift. Passer à encodeDouble
et decodeDoubleForKey
pour les types NSTimeInterval
fixes aDecoder
renvoyant nil
pour ces valeurs.