首页 > 解决方案 > 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 CJ​​ournal [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 编码/编码,我在这里不需要(我认为),因此希望得到答案。

标签: iosswiftcodablestate-restoration

解决方案


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

大部分内置类型如 NSPredicate 已经符合 NSSecureCoding,所以整体上问题在你来之前就解决了。

如果您的类型具有未免费桥接到 NSCoding 类型(如 String 到 NSString)的 Codable 属性,您可以使用 NSCoder 子类方法encodeEncodable(_:forKey:)decodeDecodable(_:forKey:).


推荐阅读