如何使用 Transformer 在 Core Data 中存储 MKPolyline?

问题描述

我希望使用 Core Data 存储 MKpolyline 属性,但我能找到的唯一答案是旧的,并且使用 iOS 12 中已弃用的存档函数 (NSKeyedUnarchiver.unarchiveObjectWithData)。它们已被那些需要类的 (NSKeyedUnarchiver.unarchivedobject) 替换,并且不允许使用 MKpolyline,因为它不符合 NSCoding。 Here is the no longer supported version:

我已在 xcdatamodeld 中将该属性设置为 Transformable,并尝试创建 Transformer 函数以允许自动值转换。但是我收到错误“静态方法‘unarchivedobject(ofClass:from:)’要求‘MKpolyline’符合‘NSCoding’”。

我已经尝试了几种方法来让 MKpolyline 支持 Codable,但我似乎也无法做到这一点。

这是我的值转换器代码


import Foundation
import MapKit

@objc(MKpolylineValueTransformer)
public final class MKpolylineValueTransformer: ValueTransformer {

    override public class func transformedValueClass() -> AnyClass {
        return MKpolyline.self
    }

    override public class func allowsReverseTransformation() -> Bool {
        return true
    }
    
    override public func transformedValue(_ value: Any?) -> Any? {
            guard let polyline = value as? MKpolyline else { return nil }
            
            do {
                let data = try NSKeyedArchiver.archivedData(withRootObject: polyline,requiringSecureCoding: true)
                return data
            } catch {
                assertionFailure("Failed to transform `MKpolyline` to `Data`")
                return nil
            }
        }
        
        override public func reverseTransformedValue(_ value: Any?) -> Any? {
            guard let data = value as? NSData else { return nil }
            
            do {
                let polyline = NSKeyedUnarchiver.unarchivedobject(ofClass: MKpolyline,from: data as Data)
                return polyline
            } catch {
                assertionFailure("Failed to transform `Data` to `MKpolyline`")
                return nil
            }
        }
}

extension MKpolylineValueTransformer {

    /// Register the transformer.

    static let name = NSValueTransformerName(rawValue: String(describing: MKpolylineValueTransformer.self))

    public static func register() {
        let transformer = MKpolylineValueTransformer()
        ValueTransformer.setValueTransformer(transformer,forName: name)
    }
}

作为另一种方法,我在折线中获取点并构建了一个自定义类来存储数据。这主要是因为我可以成功存储对象,但 NSUnarchive 返回 nil 导致“致命错误:在解包可选值时意外发现 nil”。

代码如下:


import Foundation
import MapKit

public extension MKMultiPoint {
    var coordinates: [CLLocationCoordinate2D] {
        var coords = [CLLocationCoordinate2D](repeating: kCLLocationCoordinate2DInvalid,count: pointCount)
        getCoordinates(&coords,range: NSRange(location: 0,length: pointCount))
        return coords
    }
}

class CodableCoordinate: NSObject,NSSecureCoding {
    static var supportsSecureCoding: Bool = true
    
    var latitude: Double = 0
    var longitude: Double = 0
    
    init(latitude: Double,longitude: Double) {
        self.latitude = latitude
        self.longitude = longitude
    }
    
    required init(coder aDecoder: NSCoder) {
        super.init()
        
        latitude = aDecoder.decodeDouble(forKey: "latitude")
        longitude = aDecoder.decodeDouble(forKey: "longitude")
    }

    func encode(with coder: NSCoder) {
        coder.encode(latitude,forKey: "latitude")
        coder.encode(longitude,forKey: "longitude")
    }

}

class CodableCoordinatesArray: NSObject,NSSecureCoding {
    static var supportsSecureCoding: Bool = true
    var coordinatesArray: [CodableCoordinate]

    init(coordinatesArray: [CodableCoordinate]) {
        self.coordinatesArray = coordinatesArray
    }
    
    required init(coder aDecoder: NSCoder) {
        let x = aDecoder.decodeObject(forKey:"coordinatesArray")
        coordinatesArray = aDecoder.decodeObject(forKey: "coordinatesArray") as! [CodableCoordinate]
    }
    
    convenience init(fromMKpolyline polyline: MKpolyline) {
        self.init(coordinatesArray: [CodableCoordinate]())
        for coord in polyline.coordinates {
            coordinatesArray.append(CodableCoordinate(latitude: coord.latitude,longitude: coord.longitude))
        }
    }
 
    func encode(with coder: NSCoder) {
        coder.encode(coordinatesArray,forKey:"coordinatesArray")
    }

    func polyline() -> MKpolyline? {
        if coordinatesArray.isEmpty { return nil }
        var coords = [CLLocationCoordinate2D]()
        for coord in coordinatesArray {
            coords.append(CLLocationCoordinate2D(latitude: coord.latitude,longitude: coord.longitude))
        }
        return MKpolyline(coordinates: coords,count: coords.count)
    }
}


@objc(MKpolylineValueTransformer)
public final class MKpolylineValueTransformer: ValueTransformer {

    override public class func transformedValueClass() -> AnyClass {
        return MKpolyline.self
    }

    override public class func allowsReverseTransformation() -> Bool {
        return true
    }
    
    override public func transformedValue(_ value: Any?) -> Any? {
            guard let polyline = value as? MKpolyline else { return nil }
            
            do {
                let arrayFrompolyline = CodableCoordinatesArray(fromMKpolyline: polyline)
                let data = try NSKeyedArchiver.archivedData(withRootObject: arrayFrompolyline,requiringSecureCoding: true)

                return data
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError),\(nsError.userInfo)")
            }
        }
        
        override public func reverseTransformedValue(_ value: Any?) -> Any? {
            
            guard let data = value as? NSData else { return nil }
            
            do {
                let coordinatesArray = try NSKeyedUnarchiver.unarchivedobject(ofClass: CodableCoordinatesArray.self,from: data as Data)
                return coordinatesArray?.polyline()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError),\(nsError.userInfo)")
            }
        }
}

extension MKpolylineValueTransformer {
    static let name = NSValueTransformerName(rawValue: String(describing: MKpolylineValueTransformer.self))

    /// Registers the value transformer
    public static func register() {
        let transformer = MKpolylineValueTransformer()
        ValueTransformer.setValueTransformer(transformer,forName: name)
    }
}

仅供参考,包含以下行是为了让我在投射前检查解码:

        let x = aDecoder.decodeObject(forKey:"coordinatesArray")

谢谢

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)