Swift Codable:标记对象以进行状态恢复

Posted

技术标签:

【中文标题】Swift Codable:标记对象以进行状态恢复【英文标题】:Swift Codable: marking an object to work with state restoration 【发布时间】:2020-08-15 19:13:32 【问题描述】:

我有一个 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

所以我在CJDataViewControllerFilters 类中添加了Codable 作为协议,并添加了基本一致性:

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

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

有关使您的 NSObject 类符合 NSSecureCoding 的示例,请参阅github.com/mattneub/Programming-ios-Book-Examples/blob/…。 所以它是 NSCoding(或 NSSecureCoding),而不是 Codable。当我向 NSCoding 添加基本一致性时,它会显示“在隐式生成的 super.init 调用中未初始化属性‘self.filterStyle’”……可能是因为我有一个接受“filterStyle”的初始化程序。所以我应该使用它的原始值手动编码/解码枚举? 当然,那会很好用;我自己做那种事情。 另外请注意,如果您的枚举是 Codable,您可以使用 NSCoder 子类方法 encodeEncodable(_:forKey:)decodeDecodable(_:forKey:) 将其纳入 NSCoding 情况。我会将其添加到我的答案中。

以上是关于Swift Codable:标记对象以进行状态恢复的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中实例化一个新的 Codable 对象的最简单方法是啥?

Swift Codable 将空 json 解码为 nil 或空对象

swift 中使用Codable进行数据解析

Swift Codable 多种类型

Swift 使用Codable协议进行json转模型

使用 Swift 4 的 Codable 进行解码时,是啥阻止了我从 String 到 Int 的转换?