簡體   English   中英

如何修復“NSKeyedUnarchiveFromData”不應該用於取消歸檔並將在未來版本中刪除的錯誤?

[英]How to fix the ''NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release' error?

我正在使用 Core Data 進行持久存儲,但出現下面列出的錯誤。 我查看了消息,我知道它與我使用的是可轉換和自定義類的事實有關。 盡管我進行了研究,但我不知道如何解決它。 我試圖遵守 NSSecureCoding 協議的嘗試失敗了。 我發布我的原始代碼是因為我認為從頭開始嘗試解決問題可能比嘗試修復我在 NSSecureCoding 上的糟糕嘗試更容易。 先感謝您! 任何幫助深表感謝。

'NSKeyedUnarchiveFromData' 不應用於取消歸檔,並將在未來版本中刪除

我的實體: 在此處輸入圖片說明

我的自定義類:

public class SelectedImages: NSObject, NSCoding {
    public var images: [SelectedImage] = []
    enum Key: String {
        case images = "images"
    }
    init(images: [SelectedImage]) {
        self.images = images
    }
    public func encode(with aCoder: NSCoder) {
        aCoder.encode(images, forKey: Key.images.rawValue)
    }
    public required convenience init?(coder aDecoder: NSCoder) {
        let mImages = aDecoder.decodeObject(forKey: Key.images.rawValue) as! [SelectedImage]
        self.init(images: mImages)
    }
}

public class SelectedImage: NSObject, NSCoding {
    public var location: Int = 0
    public var duration: Int = 10
    public var localIdentifier: String = ""
    
    enum Key: String {
        case location = "location"
        case duration = "duration"
        case localIdentifier = "localIdentifier"
    }
    init(location: Int, duration: Int, localIdentifier: String) {
        self.location = location
        self.duration = duration
        self.localIdentifier = localIdentifier
    }
    public override init() {
        super.init()
    }
    public func encode(with aCoder: NSCoder) {
        aCoder.encode(location, forKey: Key.location.rawValue)
        aCoder.encode(duration, forKey: Key.duration.rawValue)
        aCoder.encode(localIdentifier, forKey: Key.localIdentifier.rawValue)
    }
    public required convenience init?(coder aDecoder: NSCoder) {
        let mlocation = aDecoder.decodeInt32(forKey: Key.location.rawValue)
        let mduration = aDecoder.decodeInt32(forKey: Key.duration.rawValue)
        let mlocalIdentifier = aDecoder.decodeObject(forKey: Key.localIdentifier.rawValue) as! String
        self.init(location: Int(mlocation), duration:Int(mduration), localIdentifier:String(mlocalIdentifier))
    }
}

視圖控制器:

guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let userEntity = NSEntityDescription.entity(forEntityName: "EntityTest", in: managedContext)!
let selectedImages = NSManagedObject(entity: userEntity, insertInto: managedContext) as! EntityTest
let mImages = SelectedImages(images: selectionArrays)
selectedImages.setValue(mImages, forKeyPath: "image")
        
do {
    try managedContext.save()
    print("Images saved to core data")
} catch let error as NSError {
    print("Could not save. \(error), \(error.userInfo)")
}
    let newViewController = PickerTest6()
    self.navigationController?.pushViewController(newViewController, animated: true)

我還沒有運行這段代碼,但它應該可以工作。

  1. SelectedImage類進行更改。
public class SelectedImage: NSObject, NSSecureCoding { // Class must inherit from NSSecureCoding
    public static var supportsSecureCoding: Bool = true // It's the required property
    
    public var location: Int = 0
    public var duration: Int = 10
    public var localIdentifier: String = ""
    
    private enum CodingKeys: String {
        case location, duration, localIdentifier
    }
    
    public override init() {
        super.init()
    }
    
    init(location: Int, duration: Int, localIdentifier: String) {
        self.location = location
        self.duration = duration
        self.localIdentifier = localIdentifier
    }
    
    public required init?(coder: NSCoder) {
        self.location = coder.decodeInteger(forKey: CodingKeys.location.rawValue)
        self.duration = coder.decodeInteger(forKey: CodingKeys.duration.rawValue)
        
        // Now instead of decodeObject(forKey:) you should use decodeObject(of: forKey:).
        self.localIdentifier = coder.decodeObject(of: NSString.self, forKey: CodingKeys.localIdentifier.rawValue) as String? ?? ""
    }
    
    public func encode(with coder: NSCoder) {
        coder.encode(location, forKey: CodingKeys.location.rawValue)
        coder.encode(duration, forKey: CodingKeys.duration.rawValue)
        coder.encode(localIdentifier, forKey: CodingKeys.localIdentifier.rawValue)
    }
}
  1. 創建SelectedImageTransformer類。
@objc(SelectedImageTransformer)
final class SelectedImageTransformer: NSSecureUnarchiveFromDataTransformer {
    static let name = NSValueTransformerName(rawValue: String(describing: SelectedImageTransformer.self))
    
    override class var allowedTopLevelClasses: [AnyClass] {
        return super.allowedTopLevelClasses + [SelectedImage.self]
    }

    public class func register() {
        let transformer = SelectedImageTransformer()
        ValueTransformer.setValueTransformer(transformer, forName: name)
    }
}
  1. 按如下方式編輯 CoreData 模型。

在此處輸入圖片說明

  1. 在初始化持久容器之前調用AppDelegate 中的 register 方法(如果您使用 UIKit)。
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
    // Register the transformer
    SelectedImageTransformer.register()
    
    let container = NSPersistentContainer(name: "AppName")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

有關更多詳細信息,您可以閱讀這篇這篇文章。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM