42

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

@interface Person : NSObject <NSCoding>

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

@end

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

  1. initWithCoderencodeWithCoder

  2. [NSKeyedArchiver archivedDataWithRootObject:person]

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

但是我需要将此应用程序移至 iOS 8,并且该类将被快速编码并为这个新的 iOS 8 版本的应用程序“重命名”。

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

当我尝试取消归档对象时,出现以下错误:

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

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

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

4

5 回答 5

66

这可能是另一种解决方案,这就是我所做的(因为当时我没有使用 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];
于 2014-11-05T10:27:04.817 回答
27

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

@objc(Person)
class PersonOldVersion: NSObject, NSCoding {
    var name = ""
    var lastName = ""
}
于 2014-09-01T06:04:32.703 回答
17

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

在我复制原始目标以获得我的产品的 2 个构建之后,在 Swift 项目中遇到了类似的问题。这两个构建需要可互换使用。

所以,我有类似 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
}
于 2016-01-07T16:27:01.573 回答
5

我认为您可以按以下方式解决它:

@implementation PersonOldVersion

+ (void)load
{
    [NSKeyedUnarchiver setClass:[PersonOldVersion class] forClassName:@"Person"];
}
于 2018-03-16T05:30:08.430 回答
1

newacct 的回答帮助了我的类名,但我也遇到了一个问题,我在我的 Swift 类中从我的 Objective-C 类中更改了一个变量名。也使用@objc()固定的:

老班:

@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

新班级:

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

我还意识到我正在使用encodeObject decodeObjectForKey值类型,这导致我的 Swift 类出现问题。切换到encodeDoubledecodeDoubleForKey为这些值NSTimeInterval固定aDecoder返回的类型。nil

于 2016-09-28T14:14:56.927 回答