Skip to content

How to use JSON in Core Data #31

Description

@cjmconie

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:

  1. Add NSCoding conformance to JSON allowing the attribute's type to be Transformable.
    • This does not seem technically possible as mentioned above.
  2. Use a custom ValueTransformer.
    • This is not possible because JSON does not derive from NSObject.
  3. 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.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions