当原始类不可用时,如何解码对象?

Ang*_*han 38 nscoding ios nskeyedunarchiver swift

我有一个iOS 7应用程序,它将自定义对象作为文件保存到应用程序的iCloud Docs文件夹中.为此,我使用了NSCoding协议.

@interface Person : NSObject <NSCoding>

    @property (copy, nonatomic) NSString *name
    @property (copy, nonatomic) NSString *lastName

@end
Run Code Online (Sandbox Code Playgroud)

对象序列化在iOS 7版本的应用程序中完美运行:

  1. initWithCoderencodeWithCoder

  2. [NSKeyedArchiver archivedDataWithRootObject:person]

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

但我需要将此应用程序移至iOS 8,此类将以swift编码,并为此iOS应用程序的新版本重新命名.

class PersonOldVersion: NSObject, NSCoding {
    var name = ""
    var lastName = ""
}
Run Code Online (Sandbox Code Playgroud)

当我尝试取消归档该对象时,我收到以下错误:

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

我已经尝试将swift类'PersonOldVersion'重命名为原始类名('Person'),但仍然失败.

如何解码原始类不可用的对象?

Fer*_*nch 59

这可能是另一种解决方案,这就是我所做的(因为我不使用Swift).

在我的例子中,我存档了一个"City"类的对象,但后来将该类重命名为"CityLegacy",因为我创建了一个全新的"City"类.

我必须这样做才能将旧的"City"对象解压缩为"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];
Run Code Online (Sandbox Code Playgroud)


new*_*cct 28

如果Objective-C中类的名称很重要,则需要显式指定名称.否则,Swift将提供一些受损的名称.

@objc(Person)
class PersonOldVersion: NSObject, NSCoding {
    var name = ""
    var lastName = ""
}
Run Code Online (Sandbox Code Playgroud)

  • 这也解决了创建Today扩展和在两个项目(app本身和Today小部件)之间共享类的问题.谢谢! (3认同)

nsp*_*ire 15

这是Ferran Maylinch上面的答案的Swift翻译.

在复制原始目标之后,在Swift项目中遇到了类似的问题,以便拥有我的产品的2个版本.2个版本需要可互换使用.

所以,我有像myapp_light.app和app_pro.app这样的东西.设置类修复了这个问题.

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
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我认为你可以按如下方式解决:

@implementation PersonOldVersion

+ (void)load
{
    [NSKeyedUnarchiver setClass:[PersonOldVersion class] forClassName:@"Person"];
}
Run Code Online (Sandbox Code Playgroud)