Core Data Interop
How should JSON properties be used in conjunction with Core Data?
Discussion
JSON neatly solves the case where a Swift type needs to be created from a freeform json string (i.e. the json schema is unknown at compile time and subject to change). Furthermore, it allows the json to modelled in a type safe way.
Codable conformance allows the type to be easily converted to and from Data. This makes persisting the type to disk as data relatively simple.
However using the JSON type in the context of Core Data poses challenges. JSON was designed as a pure Swift type whereas Core Data has is origin in Objective-C.
The issue is that using a property of type JSON on an NSManagedObject subclass is not permitted. The compiler produces an error:
class Person: NSManagedObject {
@NSManaged var firstName: String
@NSManaged var lastName: String
@NSManaged var metaData: JSON // Property cannot be marked @NSManaged because its type cannot be represented in Objective-C
}
This is expected since Core Data does not support JSON out of the box, and it turns out, the metaData attribute cannot be marked as Transformable since Swift Enums with associated values (which JSON is built upon) cannot be represented in Objective-C and so conformance to NSCoding seems unlikely.
By contrast Swift dictionaries, say of type [String: Any] can be used on an NSManagedObject subclass directly since they conform to NSCoding and so their corresponding model attribute can be marked as Transformable.
Options
How then should properties of type JSON be used in the context of Core Data? Or, does Core Data's tight integration with Objective-C mean the JSON type cannot be used?
Some options which come to mind:
- Add
NSCoding conformance to JSON allowing the attribute's type to be Transformable.
- This does not seem technically possible as mentioned above.
- Use a custom ValueTransformer.
- This is not possible because
JSON does not derive from NSObject.
- Add a
toDictionary() and fromDictionary methods facilitating [String: Any] transformations.
- The attribute type will be
Transformable with a custom setter and getter in the NSManagedObject's subclass to do the transformation.
- This seems a bit heavy handed. The transformation cost will be paid on each get or set.
Are they other ways to do this? (I am relatively new to Core Data).
Example Object
class Person: NSManagedObject {
@NSManaged var firstName: String
@NSManaged var lastName: String
@NSManaged var metaData: JSON // Property cannot be marked @NSManaged because its type cannot be represented in Objective-C
}
let personAData: Data = """
{
"firstName": "John",
"lastName": "Appleseed",
"metaData": {
"foo": "bar",
"rah": [1, 2, 3]
}
}
""".data(using: .utf8)!
let personBData: Data = """
{
"firstName": "Joe",
"lastName": "Lemon",
"metaData": {
"yaz": {
"tar": 1234.00
}
}
}
""".data(using: .utf8)!
Here the metaData property needs to hold and store flexible json which makes JSON a good candidate.
Core Data Interop
How should
JSONproperties be used in conjunction with Core Data?Discussion
JSONneatly solves the case where a Swift type needs to be created from a freeform json string (i.e. the json schema is unknown at compile time and subject to change). Furthermore, it allows the json to modelled in a type safe way.Codableconformance allows the type to be easily converted to and fromData. This makes persisting the type to disk as data relatively simple.However using the
JSONtype in the context of Core Data poses challenges.JSONwas designed as a pure Swift type whereas Core Data has is origin in Objective-C.The issue is that using a property of type
JSONon anNSManagedObjectsubclass is not permitted. The compiler produces an error:This is expected since Core Data does not support
JSONout of the box, and it turns out, themetaDataattribute cannot be marked asTransformablesince Swift Enums with associated values (whichJSONis built upon) cannot be represented in Objective-C and so conformance toNSCodingseems unlikely.By contrast Swift dictionaries, say of type
[String: Any]can be used on anNSManagedObjectsubclass directly since they conform toNSCodingand so their corresponding model attribute can be marked asTransformable.Options
How then should properties of type
JSONbe used in the context of Core Data? Or, does Core Data's tight integration with Objective-C mean theJSONtype cannot be used?Some options which come to mind:
NSCodingconformance toJSONallowing the attribute's type to beTransformable.JSONdoes not derive fromNSObject.toDictionary()andfromDictionarymethods facilitating[String: Any]transformations.Transformablewith a custom setter and getter in theNSManagedObject's subclass to do the transformation.Are they other ways to do this? (I am relatively new to Core Data).
Example Object
Here the
metaDataproperty needs to hold and store flexible json which makesJSONa good candidate.