With iOS 12.1, unarchiveObject(withFile:)
was deprecated.
How can you convert NSKeyedUnarchiver.unarchiveObject(withFile: String)
to use a call to NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data: Data)
, or NSKeyedUnarchiver.unarchivedObject(ofClasses: [AnyClass]
, from: Data), or NSKeyedUnarchiver.unarchivedObject(ofClass: NSCoding.Protocol, from: Data)
?
I'm guessing you have to have something like let fileData = try Data(contentsOf: URL)
and then use one of those methods to unarchive the data. But, I cannot figure it out and the documentation accompanying the depreciation is not helpful (at least to me).
The archived data is rather simple -- just an array of strings (an array of class NameToBeSaved
as defined by this code):
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()
}
Here is the code calling 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()
}
}
I don't know if this is the best solution, but this solved the conversion for me (old code commented out for comparison):
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()
}
*/
}
Problem: unarchive an sks file for use as an SKEmitterNode.
OLD METHOD, DEPRECATED:
let filePath = Bundle.main.path(forResource: "myParticleEmitter", ofType: "sks")!
let burnerPathUnarchived = NSKeyedUnarchiver.unarchiveObject(withFile: burnerPath) as! SKEmitterNode
NEW METHOD:
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")
}
Then you can do:
mySKEffectNode.addChild(unarchivedData)
mySKSpriteNode.addChild(mySKEffectNode)
Swift 5, drop prefix 'NS' and concentrates usage for future changes...
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
}
}
}
As suggested by Apple, we should use FileManager for read/write the archived file.
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With