Giter Site home page Giter Site logo

groot's Introduction

Groot

Carthage compatible

Groot provides a simple way of serializing Core Data object graphs from or into JSON.

Groot uses annotations in the Core Data model to perform the serialization and provides the following features:

  1. Attribute and relationship mapping to JSON key paths.
  2. Value transformation using named NSValueTransformer objects.
  3. Object graph preservation.
  4. Support for entity inheritance

Installing Groot

Using CocoaPods

Add the following to your Podfile:

use_frameworks!
pod ‘Groot’

Or, if you need to support iOS 6 / OS X 10.8:

pod ‘Groot/ObjC’

Then run $ pod install.

If you don’t have CocoaPods installed or integrated into your project, you can learn how to do so here.

Using Carthage

Add the following to your Cartfile:

github “gonzalezreal/Groot”

Then run $ carthage update.

Follow the instructions in Carthage’s README to add the framework to your project.

You may need to set Embedded Content Contains Swift Code to YES in the build settings for targets that only contain Objective-C code.

Getting started

Consider the following JSON describing a well-known comic book character:

{
    "id": "1699",
    "name": "Batman",
    "real_name": "Bruce Wayne",
    "powers": [
        {
            "id": "4",
            "name": "Agility"
        },
        {
            "id": "9",
            "name": "Insanely Rich"
        }
    ],
    "publisher": {
        "id": "10",
        "name": "DC Comics"
    }
}

We could translate this into a Core Data model using three entities: Character, Power and Publisher.

Model

Mapping attributes and relationships

Groot relies on the presence of certain key-value pairs in the user info dictionary associated with entities, attributes and relationships to serialize managed objects from or into JSON. These key-value pairs are often referred in the documentation as annotations.

In our example, we should add a JSONKeyPath in the user info dictionary of each attribute and relationship specifying the corresponding key path in the JSON:

  • id for the identifier attribute,
  • name for the name attribute,
  • real_name for the realName attribute,
  • powers for the powers relationship,
  • publisher for the publisher relationship,
  • etc.

Attributes and relationships that don't have a JSONKeyPath entry are not considered for JSON serialization or deserialization.

Value transformers

When we created the model we decided to use Integer 64 for our identifier attributes. The problem is that, for compatibility reasons, the JSON uses strings for id values.

We can add a JSONTransformerName entry to each identifier attribute's user info dictionary specifying the name of a value transformer that converts strings to numbers.

Groot provides a simple way for creating and registering named value transformers:

// Swift

func toString(value: Int) -> String? {
    return "\(value)"
}

func toInt(value: String) -> Int? {
    return value.toInt()
}

NSValueTransformer.setValueTransformerWithName("StringToInteger", transform: toString, reverseTransform: toInt)
// Objective-C

[NSValueTransformer grt_setValueTransformerWithName:@"StringToInteger" transformBlock:^id(NSString *value) {
    return @([value integerValue]);
} reverseTransformBlock:^id(NSNumber *value) {
    return [value stringValue];
}];

Object graph preservation

To preserve the object graph and avoid duplicating information when serializing managed objects from JSON, Groot needs to know how to uniquely identify your model objects.

In our example, we should add an identityAttributes entry to the Character, Power and Publisher entities user dictionaries with the value identifier.

For more information about annotating your model have a look at Annotations.

Serializing from JSON

Now that we have our Core Data model ready we can start adding some data.

// Swift

let batmanJSON: JSONObject = [
    "name": "Batman",
    "id": "1699",
    "powers": [
        [
            "id": "4",
            "name": "Agility"
        ],
        [
            "id": "9",
            "name": "Insanely Rich"
        ]
    ],
    "publisher": [
        "id": "10",
        "name": "DC Comics"
    ]
]

let batman: Character = try objectFromJSONDictionary(batmanJSON, inContext: context)
// Objective-C

Character *batman = [GRTJSONSerialization objectWithEntityName:@"Character"
                                            fromJSONDictionary:batmanJSON
                                                     inContext:self.context
                                                         error:&error];

If we want to update the object we just created, Groot can merge the changes for us:

// Objective-C

NSDictionary *updateJSON = @{
    @"id": @"1699",
    @"real_name": @"Bruce Wayne",
};

// This will return the previously created managed object
Character *batman = [GRTJSONSerialization objectWithEntityName:@"Character"
                                            fromJSONDictionary:updateJSON
                                                     inContext:self.context
                                                         error:&error];

Serializing relationships from identifiers

Suppose that our API does not return full objects for the relationships but only the identifiers.

We don't need to change our model to support this situation:

// Objective-C

NSDictionary *batmanJSON = @{
    @"name": @"Batman",
    @"real_name": @"Bruce Wayne",
    @"id": @"1699",
    @"powers": @[@"4", @"9"],
    @"publisher": @"10"
};

Character *batman = [GRTJSONSerialization objectWithEntityName:@"Character"
                                            fromJSONDictionary:batmanJSON
                                                     inContext:self.context
                                                         error:&error];

The above code creates a full Character object and the corresponding relationships pointing to Power and Publisher objects that just have the identifier attribute populated.

We can import powers and publisher from different JSON objects and Groot will merge them nicely:

// Objective-C

NSArray *powersJSON = @[
    @{
        @"id": @"4",
        @"name": @"Agility"
    },
    @{
        @"id": @"9",
        @"name": @"Insanely Rich"
    }
];

[GRTJSONSerialization objectsWithEntityName:@"Power"
                              fromJSONArray:powersJSON
                                  inContext:self.context
                                      error:&error];

NSDictionary *publisherJSON = @{
    @"id": @"10",
    @"name": @"DC Comics"
};

[GRTJSONSerialization objectWithEntityName:@"Publisher"
                        fromJSONDictionary:publisherJSON
                                 inContext:self.context
                                     error:&error];

Note that serializing relationships from identifiers only works with entities specifying only one attribute as the value of identityAttributes annotation.

For more serialization methods check GRTJSONSerialization.h and Groot.swift.

Entity inheritance

Groot supports entity inheritance via the entityMapperName annotation.

If you are using SQLite as your persistent store, Core Data implements entity inheritance by creating one table for the parent entity and all child entities, with a superset of all their attributes. This can obviously have unintended performance consequences if you have a lot of data in the entities, so use this feature wisely.

Serializing to JSON

Groot provides methods to serialize managed objects back to JSON:

// Swift

let JSONDictionary = JSONDictionaryFromObject(batman)
// Objective-C

NSDictionary *JSONDictionary = [GRTJSONSerialization JSONDictionaryFromObject:batman];

For more serialization methods check GRTJSONSerialization.h and Groot.swift.

Contact

Guillermo Gonzalez
@gonzalezreal

License

Groot is available under the MIT license.

groot's People

Contributors

gonzalezreal avatar andresousa avatar oriolblanc avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.