✍️ Note
Some codes and contents are sourced from Apple’s official documentation. This post is for personal notes where I summarize the original contents to grasp the key concepts
Reference
- https://developer.apple.com/documentation/foundation/nscoding
- https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Archiving/Archiving.html#//apple_ref/doc/uid/10000047i
Archives and serializations are two ways in which you can create architecture-independent byte streams of hierarchical data. Byte streams can then be written to a file or transmitted to another process, perhaps over a network. When the byte stream is decoded, the hierarchy is regenerated. Archives provide a detailed record of a collection of interrelated objects and values. Serializations record only the simple hierarchy of property-list values
Apple
Example 1, Conforms NSCoding
class Person: NSObject, NSCoding { var name: String var age: Int var friend: Person? init(name: String, age: Int, friend: Person? = nil) { self.name = name self.age = age self.friend = friend } required convenience init?(coder: NSCoder) { guard let name = coder.decodeObject(forKey: "name") as? String else { return nil } let age = coder.decodeInteger(forKey: "age") let friend = coder.decodeObject(forKey: "friend") as? Person self.init(name: name, age: age, friend: friend) } func encode(with coder: NSCoder) { coder.encode(name, forKey: "name") coder.encode(age, forKey: "age") coder.encode(friend, forKey: "friend") }}
func savePerson(_ person: Person, to path: String) { do { let data = try NSKeyedArchiver.archivedData(withRootObject: person, requiringSecureCoding: false) try data.write(to: URL(fileURLWithPath: path)) print("Saved Person") } catch { print("Failed: \(error)") }}func loadPerson(from path: String) -> Person? { do { let data = try Data(contentsOf: URL(fileURLWithPath: path))//Instead unarchiveTopLevelObjectWithData You can use unarchivedObject(ofClass:from:) when you conforms NSSecureCoding protocol if let loadedPerson = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? Person { return loadedPerson } } catch { print("Failed: \(error)") } return nil}let friend = Person(name: "Bob", age: 35)let person = Person(name: "Alice", age: 30, friend: friend)let filePath = NSTemporaryDirectory() + "person_with_friend.archive"savePerson(person, to: filePath)if let loadedPerson = loadPerson(from: filePath) { if let loadedFriend = loadedPerson.friend { print("Person: \(loadedPerson.name), \(loadedPerson.age)") print("Friend: \(loadedFriend.name), \(loadedFriend.age)") } else { print("No friends") }}

Example 2. Conforms NSSecureCoding

In example 1, You may see this warning. unarchiveTopLevelObjectWithData was deprecated. To resolve it, let’s conforms NSSecureCoding.


class Person: NSObject, NSSecureCoding { static var supportsSecureCoding = true var name: String var age: Int var friend: Person? init(name: String, age: Int, friend: Person? = nil) { self.name = name self.age = age self.friend = friend } required convenience init?(coder: NSCoder) { guard let name = coder.decodeObject(forKey: "name") as? String else { return nil } let age = coder.decodeInteger(forKey: "age") let friend = coder.decodeObject(forKey: "friend") as? Person self.init(name: name, age: age, friend: friend) } func encode(with coder: NSCoder) { coder.encode(name, forKey: "name") coder.encode(age, forKey: "age") coder.encode(friend, forKey: "friend") }}
func savePerson(_ person: Person, to path: String) { do { let data = try NSKeyedArchiver.archivedData(withRootObject: person, requiringSecureCoding: true) try data.write(to: URL(fileURLWithPath: path)) print("Saved Person") } catch { print("Failed: \(error)") }}func loadPerson(from path: String) -> Person? { do { let data = try Data(contentsOf: URL(fileURLWithPath: path)) if let loadedPerson = try NSKeyedUnarchiver.unarchivedObject(ofClass: Person.self, from: data) { return loadedPerson } } catch { print("Failed: \(error)") } return nil}let friend = Person(name: "Bob", age: 35)let person = Person(name: "Alice", age: 30, friend: friend)let filePath = NSTemporaryDirectory() + "person_with_friend.archive"savePerson(person, to: filePath)if let loadedPerson = loadPerson(from: filePath) { if let loadedFriend = loadedPerson.friend { print("Person: \(loadedPerson.name), \(loadedPerson.age)") print("Friend: \(loadedFriend.name), \(loadedFriend.age)") } else { print("No friends") }}


Leave a Reply