Swift Codable:标记对象以使用状态恢复

Swift Codable: marking an object to work with state restoration

我有一个 Swift class,它存储当前应用于我的视图控制器的不同类型的过滤器。我想使用状态恢复来保存它,这样如果用户离开应用程序然后回来,即使应用程序被系统终止,过滤器也会恢复。

我不确定最好的方法是什么。我相信这与 Codable 有关,但如何使它与 UIViewController encoding/decoding.

一起工作

首先,class:

@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:]: unrecognized selector sent to instance 0x6000014cb640

所以我将 Codable 作为协议添加到 CJDataViewControllerFilters class,并添加了基本一致性:

@objcMembers class CJDataViewControllerFilters: NSObject, Codable {

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

它仍然因为同样的原因崩溃。

我该如何最好地解决这个问题?有没有不同的方法来实现?另外,我如何手动 encode/decode 诸如 NSPreciate 和 NSManagedObjects 数组之类的东西?

Codable 上的大多数示例都参考了 JSON coding/encoding,我在这里不需要(我认为),因此非常感谢您的回答。

NSObject的编码和解码方式是使其符合NSCoding(现在称为NSSecureCoding)。现在您可以使用键控归档器在节省时间时将其放入编码器,并使用键控解档器在恢复时将其从编码器中取出。

大多数built-in类型如NSPredicate已经符合NSSecureCoding,所以问题在你到达之前就已经解决了。

如果您的类型具有未 toll-free 桥接到 NSCoding 类型(如 String 到 NSString)的 Codable 属性,您可以使用 NSCoder 子类方法 encodeEncodable(_:forKey:)decodeDecodable(_:forKey:) 对它们进行编码.