Swift Codable: пометка объекта для работы с восстановлением состояния

У меня есть класс Swift, в котором хранятся различные типы фильтров, применяемых в настоящее время к моему контроллеру представления. Я хочу сохранить это с помощью восстановления состояния, чтобы, если пользователь покидает приложение и возвращается, фильтры восстанавливались, даже если приложение было завершено системой.

Я не уверен, как лучше всего это сделать. Я считаю, что это как-то связано с Codable, но как заставить это работать с кодировкой/декодированием UIViewController.

Во-первых, класс:

@objcMembers class CJDataViewControllerFilters: NSObject {
    
    var selectedDateFilters = [String: Array<Date>]()
    var selectedTitleFilters = [NSManagedObject]()
    var customFilterPredicate: NSPredicate?
    var customFilterName: String?
    let filterStyle: SectionStyle
    
    init(style: SectionStyle) {
        self.filterStyle = style
        super.init()
    }
}

UIViewController (который все еще находится в Objective-C):

@interface DiaryViewController : UIViewController {

  @property (nonatomic, strong) CJDataViewControllerFilters *dataFilters;
}

и восстановление состояния вызова:

- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {

    [super encodeRestorableStateWithCoder:coder];
        
    [coder encodeObject:self.dataFilters forKey: @"DataFiltersDiary"];
}

Просто это приведет к сбою, когда приложение перейдет в фоновый режим:

2020-08-15 11:37:55.470081-0700 CJournal[11367:6382501] -[XYZApp.CJDataViewControllerFilters encodeWithCoder:]: нераспознанный селектор отправлен экземпляру 0x6000014cb640

Поэтому я добавил Codable в качестве протокола к классу CJDataViewControllerFilters и добавил базовое соответствие:

@objcMembers class CJDataViewControllerFilters: NSObject, Codable {

    func encode(to encoder: Encoder) throws {
            print("CJDataViewControllerFilters: encode")
    }
    required init(from decoder: Decoder) throws{
        print("init(from decoder)")
    }
}

До сих пор вылетает по той же причине.

Как мне лучше решить эту проблему? Есть ли другой метод реализации? Кроме того, как мне вручную кодировать/декодировать такие вещи, как NSPreciate и массив NSManagedObjects?

Большинство примеров на Codable относятся к кодированию/кодированию JSON, которое мне здесь не нужно (я думаю), поэтому был бы признателен за ответ.


person Z S    schedule 15.08.2020    source источник


Ответы (1)


Способ кодирования и декодирования NSObject состоит в том, чтобы привести его в соответствие с NSCoding (в настоящее время NSSecureCoding). Теперь вы можете использовать архиватор с ключом, чтобы получить его в кодере во время экономии времени, и использовать разархиватор с ключом, чтобы получить его из кодера во время восстановления.

Большинство встроенных типов, таких как NSPredicate, уже соответствуют NSSecureCoding, так что проблема в целом решается до того, как вы приедете.

Если ваш тип имеет свойства Codable, которые не связаны бесплатным мостом с типами NSCoding (например, String с NSString), вы можете закодировать их с помощью методов подкласса NSCoder encodeEncodable(_:forKey:) и decodeDecodable(_:forKey:).

person matt    schedule 15.08.2020
comment
Пример приведения вашего класса NSObject в соответствие с NSSecureCoding см. в github.com/mattneub/Programming-iOS-Book-Examples/blob/. - person matt; 15.08.2020
comment
Так что это NSCoding (или NSSecureCoding), а не Codable. Когда я добавляю базовое соответствие NSCoding, он говорит, что свойство «self.filterStyle» не инициализировано при неявно сгенерированном вызове super.init ... вероятно, потому, что у меня есть инициализатор, который принимает «filterStyle». Итак, я должен вручную кодировать/декодировать перечисление, используя его необработанное значение? - person Z S; 15.08.2020
comment
Конечно, это сработало бы отлично; Я сам делаю такие вещи. - person matt; 15.08.2020
comment
Также обратите внимание, что если ваше перечисление является Codable, вы можете включить его в ситуацию NSCoding, используя методы подкласса NSCoder encodeEncodable(_:forKey:) и decodeDecodable(_:forKey:). Я добавлю это к своему ответу. - person matt; 16.08.2020