Как правильно перенести старые данные, сохраненные с помощью NSKeyedArchiver, в новый формат при переходе с Objective- C на Swift - PullRequest
0 голосов
/ 06 мая 2020

Более старая версия приложения имеет NSCoding -совместимый класс (назовем его OldItem), записанный в Objective C. Этот класс имеет около 20 свойств с разными типами:

@property (nonatomic) NSInteger x;

// ...

- (id)initWithCoder:(NSCoder *)coder {

    if (self = [super init])  {
        _x = [coder decodeIntegerForKey:@"x"];
        // all 20 fields are decoded in the similar way
    }

    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder {
    [self.x encodeWithCoder:coder];
    // all 20 fields encoded in the similar way
}

Он используется в другом классе (давайте назовем его Controller) как массив:

@property (nonatomic, strong, nonnull) NSMutableArray<OldItem *> *items;

Controller также кэширует элементы на диск следующим образом:

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.items];
[data writeToFile:@"myfile.txt" options:NSDataWritingFileProtectionComplete error:nil];

Теперь мне нужно перенести OldItem на Swift, а Controller изменяет только тип обрабатываемого элемента:

@property (nonatomic, strong, nonnull) NSMutableArray<NewItem *> *items; 

Вопрос: как перенести старые данные, сохраненные в myfile.txt в предыдущей версии приложения, в новую версию?

  • В идеале новый класс имеет другое имя, например NewItem , но я готов сохранить старое имя, если оно значительно упростит миграцию.
  • Неважно, будет ли новая версия сохранять данные в тот же файл или однократно читать старый файл и перемещать данные в новый файл.
  • В этом вопросе игнорируйте любые различия между OldItem и NewItem. Считайте их прямым портом.
  • Очевидно, что NewItem все равно должен соответствовать NSCoding, и чтение / запись NewItem в файл не является проблемой.

Ответы [ 2 ]

1 голос
/ 10 мая 2020

Перенести нечего. NSCoder - это какао, а не язык; он работает одинаково независимо от того, разговариваете ли вы с ним в Objective C или Swift. Просто переведите все строки кода в Swift, и все готово. Старые архивные данные продолжают работать, потому что архив остается архивом, а кодировщик остается кодировщиком. Edit Если вопрос в том, как дать вашему классу Swift старое имя класса Objective C, чтобы в него можно было прочитать архив, обратите внимание, что Objective C MyClass и Swift MyClass имеют разные имена из-за искажения имени Swift; вы должны сказать

@objc(MyClass) class Whatever : NSObject {
0 голосов
/ 02 июня 2020

После небольшого осмотра фактическое решение:

  1. Убедитесь, что public required init?(coder: NSCoder) в классе NewItem правильно разархивирует все поля, которые вы хотите сохранить, из OldItem. Например, перечисления или преобразования числовых типов могут потребовать специальной обработки, даже если вы не меняли поля как таковые.

  2. Прямо перед разархивированием сообщите NSKeyedUnarchiver, что NewItem должен использоваться в место OldItem, используя метод NSKeyedUnarchiver.setClass.

Пример:

let archivedData = try Data(contentsOf: filePath)
NSKeyedUnarchiver.setClass(NewItem.self, forClassName: "OldItem")
let items = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(archivedData)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...