I'm experimenting with NSKeyedArchiver
because I'm looking into saving an object graph. However, there seems to be a problem with objects referencing the same instance of another object. Say, I have three classes: A
, B
and C
that reference each other like this:
A --> B <-- C
A
and C
each have a reference to the same object B
. When decoding this using NSKeyedUnarchiver
, it simply creates multiple instances of B
so that A
and B
do not reference the same object anymore.
Here's a full example:
import Foundation
class A: Codable {
var b: B
init(b: B) {
self.b = b
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.b = try container.decode(B.self, forKey: .b)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(b, forKey: .b)
}
private enum CodingKeys: String, CodingKey {
case b
}
}
class B: Codable {
init() {}
required init(from decoder: Decoder) throws {}
func encode(to encoder: Encoder) throws {}
}
class C: Codable {
var b: B
init(b: B) {
self.b = b
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.b = try container.decode(B.self, forKey: .b)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(b, forKey: .b)
}
private enum CodingKeys: String, CodingKey {
case b
}
}
class Store: Codable {
var a: A
var b: B
var c: C
init() {
b = B()
a = A(b: b)
c = C(b: b)
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.a = try container.decode(A.self, forKey: .a)
self.b = try container.decode(B.self, forKey: .b)
self.c = try container.decode(C.self, forKey: .c)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(a, forKey: .a)
try container.encode(b, forKey: .b)
try container.encode(c, forKey: .c)
}
private enum CodingKeys: String, CodingKey {
case a, b, c
}
}
let store = Store()
let archiver = NSKeyedArchiver(requiringSecureCoding: false)
try! archiver.encodeEncodable(store, forKey: NSKeyedArchiveRootObjectKey)
archiver.finishEncoding()
let unarchiver = try! NSKeyedUnarchiver(forReadingFrom: archiver.encodedData)
if let decodedStore = try! unarchiver.decodeTopLevelDecodable(Store.self, forKey: NSKeyedArchiveRootObjectKey) {
// Will print false
print(decodedStore.a.b === decodedStore.c.b)
}
Am I doing something wrong or does something like this simply not work? Or is my example flawed?
Thanks!