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

时间:2014-08-25 18:27:52

标签: ios swift nscoding nskeyedunarchiver

我有一个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]

  4. 但我需要将此应用程序移至iOS 8,此类将以swift编码并重命名为&#39;这个新的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 class&#39; PersonOldVersion&#39;到原始班级名称(&#39; Person&#39;)但仍然失败。

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

5 个答案:

答案 0 :(得分:57)

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

就我而言,我存档了一个班级&#34; City&#34;但后来将课程重命名为&#34; CityLegacy&#34;因为我创造了一个全新的城市&#34;类。

我必须这样做才能取消旧的&#34; City&#34;对象作为&#34; CityLegacy&#34;对象:

// 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];

答案 1 :(得分:27)

如果Objective-C中类的名称很重要,则需要明确指定名称。否则,Swift将提供一些错误的名称。

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

答案 2 :(得分:12)

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

在我复制原始目标以获得我的产品的2个版本后,在Swift项目中出现了类似的问题。 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
}

答案 3 :(得分:1)

newacct's answer帮助我修改了类名,但是我也遇到了一个问题,我从我的Objective-C类中更改了Swift类中的变量名。使用@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这些值。

答案 4 :(得分:1)

我认为您可以按照以下方式解决问题:

@implementation PersonOldVersion

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