Skip to content

Commit

Permalink
Merge pull request #34 from gonzalezreal/1.0
Browse files Browse the repository at this point in the history
1.0
  • Loading branch information
gonzalezreal committed Jul 19, 2015
2 parents d6de11e + d54ed7c commit e625ee5
Show file tree
Hide file tree
Showing 42 changed files with 2,707 additions and 1,085 deletions.
131 changes: 131 additions & 0 deletions Documentation/Annotations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Annotations

Entities, attributes and relationships in a managed object model have an associated **user info dictionary** in which you can specify custom metadata as key-value pairs.

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**.

You can use the **Data Model inspector** in Xcode to annotate entities, attributes and relationships:

<img src="https://cloud.githubusercontent.com/assets/373190/6988412/78b00006-da51-11e4-908a-de40c99141e8.png" alt="Data Model inspector" width=260 height=338/>

This document lists all the different keys you can use to annotate models, and the purpose of each.

## Property annotations

### `JSONKeyPath`

Using this key you can specify how your managed object’s properties (that is, attributes and relationships) map to key paths in a JSON object.

For example, consider this JSON modelling a famous comic book character:

```json
{
"id": "1699",
"name": "Batman",
"publisher": {
"id": "10",
"name": "DC Comics"
}
}
```

We could model this in Core Data using two related entities: `Character` and `Publisher`.

The `Character` entity could have `identifier` and `name` attributes, and a `publisher` to-one relationship.

The `Publisher` entity could have `identifier` and `name` attributes, and a `characters` to-many relationship.

Each of these properties should have a `JSONKeyPath` entry in their corresponding user info dictionary:

* `id` for the `identifier` attribute,
* `name` for the `name` attribute,
* `publisher` for the `publisher` relationship,
* etc.

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

Note that if we were only interested in the publisher's name, we could drop the `Publisher` entity and add a `publisherName` attribute specifying `publisher.name` as the `JSONKeyPath`.

### `JSONTransformerName`

With this key you can specify the name of a value transformer that will be used to transform values when serializing from or into JSON.

Consider the `id` key in the previous JSON. Some web APIs send 64-bit integers as strings to support languages that have trouble consuming large integers.

We should store identifier values as integers instead of strings to save space.

First we need to change the `identifier` attribute's type to `Integer 64` in both the `Character` and `Publisher` entities.

Then we add a `JSONTransformerName` entry to each `identifier` attribute's user info dictionary with the name of the value transformer: `StringToInteger`.

Finally we create the value transformer and give it the name we just used:

```objc
[NSValueTransformer grt_setValueTransformerWithName:@"StringToInteger" transformBlock:^id(NSString *value) {
return @([value integerValue]);
} reverseTransformBlock:^id(NSNumber *value) {
return [value stringValue];
}];
```
If we were not interested in serializing characters back into JSON we could omit the reverse transformation:
```objc
[NSValueTransformer grt_setValueTransformerWithName:@"StringToInteger" transformBlock:^id(NSString *value) {
return @([value integerValue]);
}];
```

## Entity annotations

### `identityAttribute`

Use this key to specify the name of the attribute that uniquely identifies instances of an entity.

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

Specifying the `identityAttribute` in an entity is essential to preserve the object graph and avoid duplicate information when serializing from JSON.

Note that specifying multiple attributes for this annotation is not currently supported.

### `entityMapperName`

If your model uses entity inheritance, use this key in the base entity to specify an entity mapper name.

An entity mapper is used to determine which sub-entity is used when deserializing an object from JSON.

For example, consider the following JSON:

```json
{
"messages": [
{
"id": 1,
"type": "text",
"text": "Hello there!"
},
{
"id": 2,
"type": "picture",
"image_url": "http://example.com/risitas.jpg"
}
]
}
```

We could model this in Core Data using an abstract base entity `Message` and two concrete sub-entities `TextMessage` and `PictureMessage`.

Then we need to add an `entityMapperName` entry to the `Message` entity's user info dictionary: `MessageMapper`.

Finally we create the entity mapper and give it the name we just used:

```objc
[NSValueTransformer grt_setEntityMapperWithName:@"MessageMapper" mapBlock:^NSString *(NSDictionary *JSONDictionary) {
NSDictionary *entityMapping = @{
@"text": @"TextMessage",
@"picture": @"PictureMessage"
};
NSString *type = JSONDictionary[@"type"];
return entityMapping[type];
}];
```
1 change: 1 addition & 0 deletions Documentation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This folder contains extended documentation for using Groot.
33 changes: 22 additions & 11 deletions Groot.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Groot"
s.version = "0.2"
s.version = "1.0"
s.summary = "From JSON to Core Data and back."

s.description = <<-DESC
Expand All @@ -12,16 +12,27 @@ Pod::Spec.new do |s|

s.author = { "Guillermo Gonzalez" => "gonzalezreal@icloud.com" }
s.social_media_url = "https://twitter.com/gonzalezreal"

s.ios.deployment_target = '6.0'
s.osx.deployment_target = '10.8'


s.source = { :git => "https://github.com/gonzalezreal/Groot.git", :tag => s.version.to_s }

s.source_files = "Groot/**/*.{h,m}"
s.private_header_files = "Groot/Private/*.h"

s.frameworks = 'Foundation', 'CoreData'


s.default_subspec = "Swift"

s.subspec "Swift" do |ss|
ss.ios.deployment_target = "7.0"
ss.osx.deployment_target = "10.9"

ss.source_files = "Groot/**/*.{swift,h,m}"
ss.private_header_files = "Groot/Private/*.h"
end

s.subspec "ObjC" do |ss|
ss.ios.deployment_target = "6.0"
ss.osx.deployment_target = "10.8"

ss.source_files = "Groot/**/*.{h,m}"
ss.private_header_files = "Groot/Private/*.h"
end

s.frameworks = "Foundation", "CoreData"
s.requires_arc = true
end
Loading

0 comments on commit e625ee5

Please sign in to comment.