如何解决unarchiveObject(withFile:)方法的弃用问题?

22

iOS 12.1中,unarchiveObject(withFile:)已被弃用。
如何将NSKeyedUnarchiver.unarchiveObject(withFile:String)转换为调用NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data:Data)NSKeyedUnarchiver.unarchivedObject(ofClasses:[AnyClass],from:Data)NSKeyedUnarchiver.unarchivedObject(ofClass:NSCoding.Protocol,from:Data)

我猜你需要像let fileData = try Data(contentsOf: URL)那样做一些事情,然后使用其中一种方法来解档数据。但我无法弄清楚它的实现方式,而随附的文档对我没有帮助。

存档的数据非常简单--只是一个字符串数组(由这段代码定义的NameToBeSaved类的数组):

class NameToBeSaved: NSObject, NSCoding {
var name: String

init(userEnteredName: String) {
    self.name = userEnteredName
    super.init()
}

func encode(with aCoder: NSCoder) {
    aCoder.encode(name, forKey: "name")
}

required init?(coder aDecoder: NSCoder) {
    name = aDecoder.decodeObject(forKey: "name") as! String
    super.init()
}

以下是调用 unarchiveObject(withFile:) 的代码 -

init() {
    if let archivedCategoryNames = NSKeyedUnarchiver.unarchiveObject(withFile: categoryNameArchiveURL.path) as? [NameToBeSaved] {
        allCategories += archivedCategoryNames
    } else {
        for category in starterCategories {
            let thisNewCategory = NameToBeSaved(userEnteredName: category)
            createNewCategory(thisNewCategory)
        }
        sortCategories()
    }
}

1
这不是答案,但是Data You Can Trust WWDC 2018 session讲述了新API与旧API之间的区别以及它们的具体内容。 - David Rönnqvist
你的问题中的代码正在编码或解码单个键。你能否也展示一下你当前调用 unarchiveObject(withFile:) 的代码? - David Rönnqvist
@DavidRönnqvist 我已更新帖子,包括调用unarchiveObject(withFile:)的代码。我也会查看您提供的链接。感谢您的帮助。 - Diskprotek
5个回答

8

我不知道这是否是最佳解决方案,但这对我解决了转换问题(旧代码已注释以供比较):

    init() {

    do {
        let rawdata = try Data(contentsOf: categoryNameArchiveURL)
        if let archivedCategoryNames = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(rawdata) as! [NameToBeSaved]? {
            allCategories += archivedCategoryNames
        }
    } catch {
        print("Couldn't read file")
        for category in starterCategories {
            let thisNewCategory = NameToBeSaved(userEnteredName: category)
            createNewCategory(thisNewCategory)
        }
        sortCategories()
    }

/*        if let archivedCategoryNames = NSKeyedUnarchiver.unarchiveObject(withFile: categoryNameArchiveURL.path) as? [NameToBeSaved] {
            allCategories += archivedCategoryNames
        } else {
            for category in starterCategories {
                let thisNewCategory = NameToBeSaved(userEnteredName: category)
                createNewCategory(thisNewCategory)
            }
            sortCategories()
        }
 */
}

5
问题:解压一个sks文件以用作SKEmitterNode。
旧方法,已过时:
let filePath = Bundle.main.path(forResource: "myParticleEmitter", ofType: "sks")!
let burnerPathUnarchived = NSKeyedUnarchiver.unarchiveObject(withFile: burnerPath) as! SKEmitterNode

新方法:

do {
    let fileURL = Bundle.main.url(forResource: "myParticleEmitter", withExtension: "sks")!
    let fileData = try Data(contentsOf: fileURL)
    let unarchivedData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(burnerData) as! SKEmitterNode
} catch {
    print("didn't work")
}

然后您可以执行:

mySKEffectNode.addChild(unarchivedData)
mySKSpriteNode.addChild(mySKEffectNode)

unarchiveTopLevelObjectWithData 现已过时,请使用 unarchivedObjectOfClass - hotdogsoup.nl

5

Swift 5, 放弃前缀“NS”并专注于未来的更改...

class KeyedUnarchiver : NSKeyedUnarchiver {
    open override class func unarchiveObject(with data: Data) -> Any? {
        do {
            let object = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSObject.self], from: data)
            return object
        }
        catch let error {
            Swift.print("unarchiveObject(with:) \(error.localizedDescription)")
            return nil
        }
    }

    open override class func unarchiveObject(withFile path: String) -> Any? {
        do {
            let data = try Data(contentsOf: URL.init(fileURLWithPath: path))
            let object = try unarchivedObject(ofClasses: [NSObject.self], from: data)
            return object
        }
        catch let error {
            Swift.print("unarchiveObject(withFile:) \(error.localizedDescription)")
            return nil
        }
    }
}

3
作为苹果建议的,我们应该使用FileManager来读写归档文件。
func archiveURL() -> URL? {
    guard let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first 
        else { return nil }

    return documentURL.appendingPathComponent("MyArchive.data")
}

func archive(customObject: CustomObject) {
    guard let dataToBeArchived = try? NSKeyedArchiver.archivedData(withRootObject: customObject, requiringSecureCoding: true), 
        let archiveURL = archiveURL() 
        else  {
        return
    }

    try? dataToBeArchived.write(to: archiveURL)
}

func unarchive() -> CustomObject? {
    guard let archiveURL = archiveURL(),
        let archivedData = try? Data(contentsOf: archiveURL),
        let customObject = (try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(archivedData)) as? CustomObject 
        else {
        return nil
    }

    return customObject
}

0

我遇到了和Saam Barrager一样的问题,但是建议使用unarchivedObjectOfClass(参见Mr Zystem的评论),它的用法如下:

if let epath = Bundle.main.url(forResource: "ParticleImpact", withExtension: "sks") {
  do {
    let data = try Data(contentsOf: epath)
    impactEmitter = try NSKeyedUnarchiver.unarchivedObject(ofClass: SKEmitterNode.self, from: data)
    // ... do something with impactEmitter ...
  } catch {
    // Tough beans
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接