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编码/编码,我在这里不需要(我认为),因此希望得到一个答案。

解决方法

编码和解码NSObject的方法是使其符合NSCoding(如今为NSSecureCoding)。现在,您可以在节省时间时使用键控存档程序将其放入编码器中,并在还原时使用键控取消存档器将其从编码器中移除。

大多数内置类型(例如NSPredicate)已经符合NSSecureCoding的要求,因此总体上解决了该问题。

如果您的类型具有并非免费桥接到NSCoding类型的Codable属性(如String到NSString),则可以使用NSCoder子类方法encodeEncodable(_:forKey:)decodeDecodable(_:forKey:)对它们进行编码。