首页 > 解决方案 > 编码/解码 UIBezierPath 到 CoreData 问题

问题描述

我将 UIBezierPaths 存储在 CoreData 中。为此,我必须将字段的类型设置为数据;我无法让 Transformable 工作,但确实如此。

但是,当我检索或存储这些路径时,在编码/解码过程中会出现错误。错误是

2021-11-02 09:08:39.138674+0700 TestSVG[82461:1408543] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release

我根据此处提供的帮助使用的方法是:

 func bezierToData(path: UIBezierPath) -> Data? {
        do {
            return try NSKeyedArchiver.archivedData(withRootObject: path, requiringSecureCoding: false)
        } catch {
            return nil
        }
    }
    
    func dataToBezier(src: Data) -> UIBezierPath? {
        do {
            return try NSKeyedUnarchiver.unarchivedObject(ofClass: UIBezierPath.self, from: src)!
        } catch {
            return nil
        }
    }

这似乎是苹果公司强加的多项改变。我的需求很简单,我正在做的事情很完美,但我当然不想遇到未来的问题。

这个答案:'NSKeyedUnarchiveFromData' 不应该用于取消归档,并且将在未来的版本中删除,适用于可存储为可转换的对象,我无法正常工作。同样,这里的建议是使用 Data 并且已经奏效。

我已经在这里和其他地方阅读了所有我能找到的答案,因为基本上,StackOverflow 通常会优先考虑在提出问题后立即接受的答案,并且当接受的答案过时时没有更新方法......它可能是一个燃烧的垃圾箱在获得相关答案时会感到困惑,至少对于像 moi 这样的相对新手而言。

但我离题了。谁能指出我当前的做法,这将允许我简单地将 UIBezierPaths 序列化和反序列化到 CoreData 存储中?

标签: swiftcore-datauibezierpatharchiving

解决方案


我已经尝试过了,它成功地进行了编码和解码。没有关于过时功能的警告。

这应该适用于Binary Data

func bezierToData(path: UIBezierPath) -> Data? {
    try? NSKeyedArchiver.archivedData(withRootObject: path, requiringSecureCoding: true)
}

func dataToBezier(src: Data) -> UIBezierPath? {
    try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(src) as? UIBezierPath
}


let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 100, height: 200), cornerRadius: 10)
let pathData = bezierToData(path: path)

let unarchivedPath = dataToBezier(src: pathData!)

另一种选择是创建Transformable字段并NSSecureUnarchiveFromDataTransformer在其中使用。不要忘记在 CoreData 数据模型检查器中设置这个 Transformer(并且Custom class是)。UIBeizerPath

import UIKit

class UIBezierPathToDataTransformer: NSSecureUnarchiveFromDataTransformer {
    override class func allowsReverseTransformation() -> Bool {
        return true
    }
    override class func transformedValueClass() -> AnyClass {
        return UIBezierPath.self
    }
    override class var allowedTopLevelClasses: [AnyClass] {
        return [UIBezierPath.self]
    }
    override func transformedValue(_ value: Any?) -> Any? {
        guard let data = value as? Data else {
            fatalError("Wrong data type: value must be a Data object; received \(type(of: value))")
        }
        return super.transformedValue(data)
    }
    override func reverseTransformedValue(_ value: Any?) -> Any? {
        guard let path = value as? UIBezierPath else {
            fatalError("Wrong data type: value must be a UIBezierPath object; received \(type(of: value))")
        }
        return super.reverseTransformedValue(path)
    }
}

extension NSValueTransformerName {
    static let uiBezierPathToDataTransformer = NSValueTransformerName(rawValue: "UIBezierPathDataTransformer")
}

此外,当将此添加到您创建持久容器的位置(可能在 AppDelegate 中)时:

lazy var persistentContainer: NSPersistentContainer = {
    // Register the transformer at the very beginning.
 ValueTransformer.setValueTransformer(UIBezierPathToDataTransformer(), forName: .uiBezierPathToDataTransformer) // <- HERE

let container = NSPersistentContainer(name: "CoreDataAttributes")
container.loadPersistentStores(completionHandler: { (_, error) in
    guard let error = error as NSError? else { return }
    fatalError("###\(#function): Failed to load persistent stores:\(error)")
})
  
container.viewContext.automaticallyMergesChangesFromParent = true
SampleData.generateSampleDataIfNeeded(context: container.newBackgroundContext())

return container
}()

推荐阅读