为可转换属性采用NSSecureUnarchiveFromDataTransformer时崩溃 [英] Crash when adopting NSSecureUnarchiveFromDataTransformer for a Transformable property

查看:152
本文介绍了为可转换属性采用NSSecureUnarchiveFromDataTransformer时崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在iOS 12中,Apple引入了 NSSecureUnarchiveFromDataTransformerName ,用于CoreData模型实体的Transformable属性.我曾经将变形金刚名称"字段保留为空,隐式使用了 NSKeyedUnarchiveFromDataTransformerName .现在已弃用此转换器,以后将其保留为空将意味着 NSSecureUnarchiveFromDataTransformerName .

In iOS 12 Apple introduced NSSecureUnarchiveFromDataTransformerName for use on CoreData model entities' Transformable properties. I used to keep the Transformer Name field empty, which implicitly used NSKeyedUnarchiveFromDataTransformerName. This transformer is now deprecated, and keeping the field empty in the future will mean NSSecureUnarchiveFromDataTransformerName instead.

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

In iOS 13, if that field is empty, you now get a runtime warning telling you the aforementioned. I couldn't find any documentation on this anywhere, the only reference I got was a WWDC 2018 Core Data Best Practices talk which briefly mentioned what I just said.

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

Now I have a model with an entity which directly stores HTTPURLResponse objects in a Transformable property. It conforms to NSSecureCoding, and I checked in runtime that supportsSecureCoding is true.

为Transformer Name设置 NSSecureUnarchiveFromDataTransformerName 时崩溃,并显示以下消息:

Setting NSSecureUnarchiveFromDataTransformerName for the Transformer Name crashes with this message:

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属性只能是这些顶级对象中的一个.

So it sounds like Transformable properties can only be of these top level objects.

我尝试对安全转换器进行子类化,并按照文档中的建议覆盖 allowedTopLevelClasses 属性:

I tried subclassing the secure transformer and override the allowedTopLevelClasses property as suggested by the documentation:

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

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

然后我想我可以创建一个自定义的转换器名称,在模型中进行设置,然后为该名称调用 setValueTransformer(_:forName:),但是我找不到要设置的API如果我使用的是iOS 11,则默认的 NSKeyedUnarchiveFromDataTransformer 作为我的自定义名称.

Then I'd imagine I can create a custom transformer name, set it in the model and call setValueTransformer(_:forName:) for that name, but I couldn't find API to set the default NSKeyedUnarchiveFromDataTransformer for my custom name in case I'm on iOS 11.

请记住,我正在使用Xcode 11 Beta 5,但是如果我要接受所指出的错误含义,这似乎无关紧要.

Keep in mind, I'm using Xcode 11 Beta 5, but this doesn't seem to be related if I am to accept the meaning of the error I'm getting as stated.

赞赏任何想法.

推荐答案

我编写了一个简单的模板类,可以轻松地为实现 NSSecureCoding 的任何类创建和注册一个转换器.至少在我使用 UIColor 作为可转换属性的简单测试中,它在iOS 12和13中对我来说效果很好.

I wrote a simple template class which makes it easy to create and register a transformer for any class that implements NSSecureCoding. It works fine for me in iOS 12 and 13, at least in my simple test using UIColor as the transformable attribute.

要使用它(以 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()

要在Core Data模型中使用的转换器的名称是 UIColorValueTransformer .

The name of the transformer to use in the Core Data model is 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)
  }
}

这篇关于为可转换属性采用NSSecureUnarchiveFromDataTransformer时崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆