Ответ 1
Если имя класса в Objective-C важно, вам нужно явно указать имя. В противном случае Swift предоставит некоторое искаженное имя.
@objc(Person)
class PersonOldVersion: NSObject, NSCoding {
var name = ""
var lastName = ""
}
У меня есть приложение iOS 7, которое сохраняет пользовательский объект в папку приложения iCloud Docs в виде файла. Для этого я использую протокол 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, и этот класс будет закодирован в быстрой и "переименован" для этой новой версии приложения 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"), но все еще не удается.
Как я могу декодировать объект, оригинальный класс которого недоступен?
Если имя класса в Objective-C важно, вам нужно явно указать имя. В противном случае Swift предоставит некоторое искаженное имя.
@objc(Person)
class PersonOldVersion: NSObject, NSCoding {
var name = ""
var lastName = ""
}
Это может быть другое решение, и это то, что я сделал (поскольку я не использую Swift).
В моем случае я архивировал объект класса "Город", но затем переименовал класс в "CityLegacy", потому что создал совершенно новый класс "Город".
Я должен был сделать это, чтобы удалить старый объект "Город" как объект "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 после того, как я продублировал исходную цель, чтобы иметь 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
}
Я думаю, вы могли бы решить это следующим образом:
@implementation PersonOldVersion
+ (void)load
{
[NSKeyedUnarchiver setClass:[PersonOldVersion class] forClassName:@"Person"];
}
Ответ 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. Переключение на encodeDouble
и decodeDoubleForKey
для NSTimeInterval
типов фиксированного aDecoder
возвращающихся nil
для этих значений.