对 Transformable 属性采用 NSSecureUnarchiveFromDataTransformer 时发生崩溃

2024-04-01

苹果在 iOS 12 中引入了NSSecureUnarchiveFromDataTransformerName用于 CoreData 模型实体的 Transformable 属性。我曾经将变压器名称字段保留为空,这隐式使用了NSKeyedUnarchiveFromDataTransformerName。该变压器现已弃用,将来保持该字段为空将意味着NSSecureUnarchiveFromDataTransformerName反而。

在 iOS 13 中,如果该字段为空,您现在会收到一条运行时警告,告诉您上述内容。我在任何地方都找不到任何相关文档,我得到的唯一参考是 WWDC 2018 核心数据最佳实践演讲,其中简要提到了我刚才所说的内容。

现在我有一个带有直接存储实体的模型HTTPURLResponseTransformable 属性中的对象。它符合NSSecureCoding,我在运行时检查了supportsSecureCoding is true.

Setting NSSecureUnarchiveFromDataTransformerName因为 Transformer Name 崩溃并显示以下消息:

Object of class NSHTTPURLResponse is not among allowed top level class list (
    NSArray,
    NSDictionary,
    NSSet,
    NSString,
    NSNumber,
    NSDate,
    NSData,
    NSURL,
    NSUUID,
    NSNull
) with userInfo of (null)

所以听起来 Transformable 属性只能是这些顶级对象的。

我尝试对安全变压器进行子类化并覆盖allowedTopLevelClasses文档建议的属性:

@available(iOS 12.0, *)
public class NSSecureUnarchiveHTTPURLResponseFromDataTransformer: NSSecureUnarchiveFromDataTransformer {

    override public class var allowedTopLevelClasses: [AnyClass] {
        return [HTTPURLResponse.self]
    }
}

然后我想我可以创建一个自定义变压器名称,将其设置在模型中并调用setValueTransformer(_:forName:)对于该名称,但我找不到 API 来设置默认值NSKeyedUnarchiveFromDataTransformer作为我的自定义名称,以防我使用 iOS 11。

请记住,我正在使用 Xcode 11 Beta 5,但如果我要接受我所得到的错误的含义,这似乎并不相关。

欣赏任何想法。


我编写了一个简单的模板类,它可以轻松地为任何实现的类创建和注册变压器NSSecureCoding。它在 iOS 12 和 13 中对我来说工作得很好,至少在我使用的简单测试中是这样UIColor作为可变形属性。

使用它(使用UIColor举个例子):

// Make UIColor adopt ValueTransforming
extension UIColor: ValueTransforming {
  static var valueTransformerName: NSValueTransformerName { 
    .init("UIColorValueTransformer")
  }
}

// Register the transformer somewhere early in app startup.
NSSecureCodingValueTransformer<UIColor>.registerTransformer()

核心数据模型中使用的转换器的名称是UIColorValueTransformer.

import Foundation

public protocol ValueTransforming: NSSecureCoding {
  static var valueTransformerName: NSValueTransformerName { get }
}

public class NSSecureCodingValueTransformer<T: NSSecureCoding & NSObject>: ValueTransformer {
  public override class func transformedValueClass() -> AnyClass { T.self }
  public override class func allowsReverseTransformation() -> Bool { true }

  public override func transformedValue(_ value: Any?) -> Any? {
    guard let value = value as? T else { return nil }
    return try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true)
  }

  public override func reverseTransformedValue(_ value: Any?) -> Any? {
    guard let data = value as? NSData else { return nil }
    let result = try? NSKeyedUnarchiver.unarchivedObject(
      ofClass: T.self,
      from: data as Data
    )
    return result
  }

  /// Registers the transformer by calling `ValueTransformer.setValueTransformer(_:forName:)`.
  public static func registerTransformer() {
    let transformer = NSSecureCodingValueTransformer<T>()
    ValueTransformer.setValueTransformer(transformer, forName: T.valueTransformerName)
  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对 Transformable 属性采用 NSSecureUnarchiveFromDataTransformer 时发生崩溃 的相关文章

随机推荐