<h1 style="font-size:28px;margin:0px 0px 10px;padding:0px;font-family:Helvetica,arial,freesans,clean,sans-serif">CoreData: API proposal - AGEntityMapper</h1><h2 style="margin:0px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204);font-family:Helvetica,arial,freesans,clean,sans-serif">
Background</h2><p style="margin:0px 0px 15px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">Mapping JSON representations to a &quot;rich&quot; domain model in ObjC is <a href="http://matthiaswessendorf.wordpress.com/2012/11/19/objc-json/" style="color:rgb(65,131,196);text-decoration:initial">a bit cumbersome</a>. Similar is true when mapping a JSON data/response to a NSMangedObject (and vise versa). There is a base framework for &quot;remote persistence&quot;, via the CoreData API, by leveraging a custom NSIncrementalStore -&gt; <a href="https://github.com/AFNetworking/AFIncrementalStore" style="color:rgb(65,131,196);text-decoration:initial">AFIncrementalStore</a>.</p>
<p style="margin:15px 0px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">For that,... a similar <em>two-way-mapping</em> is required, as described <a href="http://matthiaswessendorf.wordpress.com/2013/01/02/coredata-data-mapping-with-afincrementalstore/" style="color:rgb(65,131,196);text-decoration:initial">here</a>.</p>
<h2 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204);font-family:Helvetica,arial,freesans,clean,sans-serif">AeroGear and CoreData</h2>
<p style="margin:0px 0px 15px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">Our CoreData offerings are leveraging the AFIncrementalStore, therefore (as with other frameworks/libraries) we need a mapping as well. We need to know the name of the entity and we need a <code style="font-size:12px;line-height:normal;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;margin:0px 2px;padding:0px 5px;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;white-space:nowrap">NSDictionary</code> that covers the actual JSON/property mapping. It could be done with the vanialla ObjC classes:</p>
<div class="highlight" style="background-color:rgb(255,255,255);border:none;padding:0px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px"><pre style="font-size:13px;line-height:19px;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;word-wrap:break-word;margin-top:15px;margin-bottom:15px;background-color:rgb(248,248,248);border:1px solid rgb(204,204,204);overflow:auto;padding:6px 10px;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">
<span class="c1" style="color:rgb(153,153,136);font-style:italic">// some mappers:</span>
<span class="n">NSDictionary</span> <span class="o" style="font-weight:bold">*</span><span class="n">task_mapper</span> <span class="o" style="font-weight:bold">=</span>
  <span class="p">[</span><span class="n">NSDictionary</span> <span class="nl">dictionaryWithObjectsAndKeys:</span><span class="s" style="color:rgb(221,17,68)">@&quot;description&quot;</span><span class="p">,</span><span class="s" style="color:rgb(221,17,68)">@&quot;desc&quot;</span><span class="p">,</span><span class="s" style="color:rgb(221,17,68)">@&quot;id&quot;</span><span class="p">,</span><span class="s" style="color:rgb(221,17,68)">@&quot;myId&quot;</span><span class="p">,</span> <span class="nb" style="color:rgb(0,134,179)">nil</span><span class="p">];</span>
<span class="n">NSDictionary</span> <span class="o" style="font-weight:bold">*</span><span class="n">project_mapper</span> <span class="o" style="font-weight:bold">=</span>
  <span class="p">[</span><span class="n">NSDictionary</span> <span class="nl">dictionaryWithObjectsAndKeys:</span><span class="s" style="color:rgb(221,17,68)">@&quot;id&quot;</span><span class="p">,</span><span class="s" style="color:rgb(221,17,68)">@&quot;myId&quot;</span><span class="p">,</span> <span class="nb" style="color:rgb(0,134,179)">nil</span><span class="p">];</span>

<span class="c1" style="color:rgb(153,153,136);font-style:italic">// create a schema out of the mappers:</span>
<span class="n">NSDictionary</span> <span class="o" style="font-weight:bold">*</span><span class="n">schema</span> <span class="o" style="font-weight:bold">=</span>
  <span class="p">[</span><span class="n">NSDictionary</span> <span class="nl">dictionaryWithObjectsAndKeys:</span><span class="n">task_mapper</span><span class="p">,</span> <span class="s" style="color:rgb(221,17,68)">@&quot;Task&quot;</span><span class="p">,</span> <span class="n">project_mapper</span><span class="p">,</span> <span class="s" style="color:rgb(221,17,68)">@&quot;Project&quot;</span><span class="p">,</span> <span class="nb" style="color:rgb(0,134,179)">nil</span><span class="p">];</span>

<span class="c1" style="color:rgb(153,153,136);font-style:italic">// pass the schema to the AGCoreDataHelper class, when doing the init...</span>
</pre></div><h2 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204);font-family:Helvetica,arial,freesans,clean,sans-serif">Proposal for a custom API</h2>
<p style="margin:0px 0px 15px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">I&#39;d like to introduce a new wrapper type, called <code style="font-size:12px;line-height:normal;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;margin:0px 2px;padding:0px 5px;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;white-space:nowrap">AGEntityMapper</code>:</p>
<div class="highlight" style="background-color:rgb(255,255,255);border:none;padding:0px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px"><pre style="font-size:13px;line-height:19px;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;word-wrap:break-word;margin-top:15px;margin-bottom:15px;background-color:rgb(248,248,248);border:1px solid rgb(204,204,204);overflow:auto;padding:6px 10px;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">
<span class="k" style="font-weight:bold">@interface</span> <span class="nc" style="color:rgb(68,85,136);font-weight:bold">AGEnityMapper</span> : <span class="nc" style="color:rgb(68,85,136);font-weight:bold">NSObject</span>

<span class="k" style="font-weight:bold">@property</span> <span class="n">NSString</span> <span class="o" style="font-weight:bold">*</span><span class="n">name</span><span class="p">;</span>
<span class="k" style="font-weight:bold">@property</span> <span class="n">NSDictionary</span> <span class="o" style="font-weight:bold">*</span><span class="n">mapper</span><span class="p">;</span>

<span class="k" style="font-weight:bold">-</span><span class="p">(</span><span class="kt" style="color:rgb(68,85,136);font-weight:bold">id</span><span class="p">)</span> <span class="nf" style="color:rgb(153,0,0);font-weight:bold">initWithName:</span><span class="p">(</span><span class="n">NSString</span> <span class="o" style="font-weight:bold">*</span><span class="p">)</span> <span class="n">name</span> <span class="nl">mapper:</span><span class="p">(</span><span class="n">NSDictionary</span> <span class="o" style="font-weight:bold">*</span><span class="p">)</span> <span class="n">mapper</span><span class="p">;</span>
<span class="k" style="font-weight:bold">@end</span>
</pre></div><p style="margin:15px 0px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">This <code style="font-size:12px;line-height:normal;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;margin:0px 2px;padding:0px 5px;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;white-space:nowrap">AGEntityMapper</code> would be applied onto the <code style="font-size:12px;line-height:normal;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;margin:0px 2px;padding:0px 5px;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;white-space:nowrap">AGCoreDataConfig</code>:</p>
<div class="highlight" style="background-color:rgb(255,255,255);border:none;padding:0px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px"><pre style="font-size:13px;line-height:19px;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;word-wrap:break-word;margin-top:15px;margin-bottom:15px;background-color:rgb(248,248,248);border:1px solid rgb(204,204,204);overflow:auto;padding:6px 10px;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">
<span class="k" style="font-weight:bold">@protocol</span> <span class="nc" style="color:rgb(68,85,136);font-weight:bold">AGCoreDataConfig</span> <span class="o" style="font-weight:bold">&lt;</span><span class="n">NSObject</span><span class="o" style="font-weight:bold">&gt;</span>

<span class="k" style="font-weight:bold">@property</span> <span class="p">(</span><span class="n">strong</span><span class="p">,</span> <span class="n">nonatomic</span><span class="p">)</span> <span class="n">NSManagedObjectModel</span> <span class="o" style="font-weight:bold">*</span><span class="n">managedObjectModel</span><span class="p">;</span>
<span class="k" style="font-weight:bold">@property</span> <span class="p">(</span><span class="n">strong</span><span class="p">,</span> <span class="n">nonatomic</span><span class="p">)</span> <span class="n">NSURL</span> <span class="o" style="font-weight:bold">*</span><span class="n">baseURL</span><span class="p">;</span>

<span class="k" style="font-weight:bold">-</span><span class="p">(</span><span class="kt" style="color:rgb(68,85,136);font-weight:bold">void</span><span class="p">)</span><span class="nf" style="color:rgb(153,0,0);font-weight:bold">applyEntityMappers:</span><span class="p">(</span><span class="n">AGEnityMapper</span> <span class="o" style="font-weight:bold">*</span><span class="p">)</span><span class="nv" style="color:rgb(0,128,128)">firstObject</span><span class="p">,</span> <span class="p">...</span> <span class="n">NS_REQUIRES_NIL_TERMINATION</span><span class="p">;</span>

<span class="k" style="font-weight:bold">@end</span>
</pre></div><p style="margin:15px 0px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px">The actual code, would look like this:</p><div class="highlight" style="background-color:rgb(255,255,255);border:none;padding:0px;font-family:Helvetica,arial,freesans,clean,sans-serif;font-size:14px;line-height:22px;margin-bottom:0px!important">
<pre style="font-size:13px;line-height:19px;font-family:Consolas,&#39;Liberation Mono&#39;,Courier,monospace;word-wrap:break-word;margin-top:15px;margin-bottom:15px;background-color:rgb(248,248,248);border:1px solid rgb(204,204,204);overflow:auto;padding:6px 10px;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">
<span class="n">EnityMapper</span> <span class="o" style="font-weight:bold">*</span><span class="n">taskMapper</span> <span class="o" style="font-weight:bold">=</span>
  <span class="p">[[</span><span class="n">EnityMapper</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithName:</span><span class="s" style="color:rgb(221,17,68)">@&quot;Task&quot;</span>
       <span class="c1" style="color:rgb(153,153,136);font-style:italic">// mapping the properties on the &quot;entity&quot; (NSManagedObject)</span>
       <span class="c1" style="color:rgb(153,153,136);font-style:italic">// to the external representation (e.g. JSON)</span>
                             <span class="nl">mapper:</span><span class="err" style="color:rgb(166,23,23);background-color:rgb(227,210,210)">@</span><span class="p">{</span> <span class="s" style="color:rgb(221,17,68)">@&quot;desc&quot;</span><span class="o" style="font-weight:bold">:</span> <span class="s" style="color:rgb(221,17,68)">@&quot;description&quot;</span><span class="p">,</span> <span class="s" style="color:rgb(221,17,68)">@&quot;myId&quot;</span><span class="o" style="font-weight:bold">:</span> <span class="s" style="color:rgb(221,17,68)">@&quot;id&quot;</span><span class="p">}];</span>

<span class="n">EnityMapper</span> <span class="o" style="font-weight:bold">*</span><span class="n">projectMapper</span> <span class="o" style="font-weight:bold">=</span>
  <span class="p">[[</span><span class="n">EnityMapper</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithName:</span><span class="s" style="color:rgb(221,17,68)">@&quot;Project&quot;</span>
       <span class="c1" style="color:rgb(153,153,136);font-style:italic">// mapping the properties on the &quot;entity&quot; (NSManagedObject)</span>
       <span class="c1" style="color:rgb(153,153,136);font-style:italic">// to the external representation (e.g. JSON)</span>
                             <span class="nl">mapper:</span><span class="err" style="color:rgb(166,23,23);background-color:rgb(227,210,210)">@</span><span class="p">{</span> <span class="s" style="color:rgb(221,17,68)">@&quot;myId&quot;</span><span class="o" style="font-weight:bold">:</span> <span class="s" style="color:rgb(221,17,68)">@&quot;id&quot;</span><span class="p">}];</span>

<span class="n">AGCoreDataHelper</span> <span class="o" style="font-weight:bold">*</span><span class="n">helper</span> <span class="o" style="font-weight:bold">=</span> <span class="p">[[</span><span class="n">AGCoreDataHelper</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithConfig:</span><span class="o" style="font-weight:bold">^</span><span class="p">(</span><span class="kt" style="color:rgb(68,85,136);font-weight:bold">id</span><span class="o" style="font-weight:bold">&lt;</span><span class="n">AGCoreDataConfig</span><span class="o" style="font-weight:bold">&gt;</span> <span class="n">config</span><span class="p">)</span> <span class="p">{</span>

  <span class="p">[</span><span class="n">config</span> <span class="nl">setBaseURL:</span><span class="p">[</span><span class="n">NSURL</span> <span class="nl">URLWithString:</span><span class="s" style="color:rgb(221,17,68)">@&quot;<a href="http://server.com">http://server.com</a>&quot;</span><span class="p">]];</span>

  <span class="p">[</span><span class="n">config</span> <span class="nl">applyEntityMappers:</span>
    <span class="n">taskMapper</span><span class="p">,</span>
    <span class="n">projectMapper</span><span class="p">,</span>
    <span class="nb" style="color:rgb(0,134,179)">nil</span> <span class="c1" style="color:rgb(153,153,136);font-style:italic">// terminate the varargs.</span>
  <span class="p">];</span>
<span class="p">}];</span></pre></div><br>-- <br>Matthias Wessendorf<br><br>blog: <a href="http://matthiaswessendorf.wordpress.com/">http://matthiaswessendorf.wordpress.com/</a><br>sessions: <a href="http://www.slideshare.net/mwessendorf">http://www.slideshare.net/mwessendorf</a><br>
twitter: <a href="http://twitter.com/mwessendorf">http://twitter.com/mwessendorf</a><br>