※ まだ正式リリースされていない情報なので変更の可能性があります🙇
Swift3まではstruct
やenum
をデータとして保存や読み込みをする際に必要となるオブジェクトのシリアライズとデシリアライズのために一発NSCoding
プロトコルに準拠したNSObject
を噛ませなければいけませんでした😭
struct Person {
let name: String
let age: Int
}
extension Person {
class Helper: NSObject, NSCoding {
let person: Person?
init(person: Person) {
self.person = person
super.init()
}
required init?(coder aDecoder: NSCoder) {
guard
let name = aDecoder.decodeObject(forKey: "name") as? String,
let age = aDecoder.decodeObject(forKey: "age") as? Int else {
return nil
}
person = Person(name: name, age: age)
super.init()
}
func encode(with aCoder: NSCoder) {
guard let person = person else { return }
aCoder.encode(person.name, forKey: "name")
aCoder.encode(person.age, forKey: "age")
}
}
}
let person = Person(name: "Foo", age: 10)
let helper = Person.Helper(person: person)
let data = NSKeyedArchiver.archivedData(withRootObject: helper)
ただ、PersonをDataにしたいだけなのにこの手間。Swift4ではCodable
というプロトコルがFoundationに追加されて解決しました☺️
struct Person: Codable {
enum Child: String, Codable {
case son, daughter
}
let name: String
let age: Int
let children: [Child]
}
let person = Person(name: "Foo", age: 10, children: [.son, .daughter])
let data = try? JSONEncoder().encode(person)
これだけで済むのです👏エンコードを例にしましたが、定義元を見るとわかるのですがデコードも可能です。しかもSwift4で追加されたプロトコルの&
が使われている👏
/// A type that can convert itself into and out of an external representation.
public typealias Codable = Decodable & Encodable
これならAPIなどで取得したデータをパースする時の処理に外部ライブラリを使わなくても済みますね。
let person = try? JSONDecoder().decode(Person.self, from: data)
このEncoderは現在JSONEncoder
とPropertyListEncoder
のみですが、今後増えて行くと思います。
しかもこの検証をPlaygroundで行なっていたところ、バイナリデータのサイズに大きな違いがあることも分かりました🎉前者がデカいのはNSObject
を継承しているためでしょう。
let data = NSKeyedArchiver.archivedData(withRootObject: helper) // 299 bytes
let data = try? JSONEncoder().encode(person) // 53 bytes
おしまい👏