カスタムオブジェクトをアプリのiCloud Docsフォルダーにファイルとして保存するiOS 7アプリケーションがあります。これには、NSCodingプロトコルを使用します。
_@interface Person : NSObject <NSCoding>
@property (copy, nonatomic) NSString *name
@property (copy, nonatomic) NSString *lastName
@end
_
オブジェクトのシリアル化は、アプリのiOS 7バージョンで完全に機能します。
initWithCoder
およびencodeWithCoder
_[NSKeyedArchiver archivedDataWithRootObject:person]
_
person = NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)theData]
しかし、このアプリをiOS 8に移動する必要があります。このクラスは、Swiftでコーディングされ、この新しい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 'PersonOldVersion'を元のクラス名( 'Person')に名前変更しましたが、それでも失敗します。
元のクラスが利用できないオブジェクトをどのようにデコードできますか?
Objective-Cのクラスの名前が重要な場合は、名前を明示的に指定する必要があります。それ以外の場合、Swiftは、いくつかの破損した名前を提供します。
@objc(Person)
class PersonOldVersion: NSObject, NSCoding {
var name = ""
var lastName = ""
}
これは別の解決策かもしれませんが、それは私がやったことです(そのときにSwiftを使用していなかったため))。
私の場合、「City」クラスのオブジェクトをアーカイブしましたが、完全に新しい「City」クラスを作成したため、クラスの名前を「CityLegacy」に変更しました。
古い「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];
Swift上記のFerran Maylinchの回答の翻訳です。
製品の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
}
私はあなたがそれを次のように解決できると思います:
@implementation PersonOldVersion
+ (void)load
{
[NSKeyedUnarchiver setClass:[PersonOldVersion class] forClassName:@"Person"];
}
newacctの回答 はクラス名の助けとなりましたが、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クラスで問題が発生していました。これらの値に対してencodeDouble
型をdecodeDoubleForKey
型にNSTimeInterval
に修正するとaDecoder
がnil
を返すことに気付きました。