Will RestKit's dynamic mapping solve this complex JSON mapping? - ios

I am using RestKit in my app, which needs to use an existing synchronization service that structures the incoming data this way:
{
"timestamp": 000000000001,
"status" : 0,
"syncData":[
{
"errors":[],
"rows":[ {"name":"AAA", ...},
{"name":"BBB", ...},
...],
"rtype":"FOO" },
{
"errors":[],
"rows":[ {"id":1, "description":"ZZZ", ....},
{"id":2, "description":"YYY", ....},
...],
"rtype":"BAR"
}, ...
I'm new to RestKit and trying to figure out the best way to solve this problem, and the complementary problem of sending this same structure of data back to the server. I'm using Core Data with RestKit.
I've mapped a SyncResponse entity to hold the top level data, and what I want to get out of this is a collection of FOO objects, "AAA", "BBB", etc., and a collection of BAR objects, "ZZZ", "YYY", etc., and a few dozen other collections of objects whose Class is indicated by the "rtype" field.
I've read the doc section on dynamic mapping and some example code and postings here, but I don't see how dynamic mapping works in this case as it is not of the {"a":{is A}, "b":{is B}} format. Is this possible using dynamic mapping, and if so, what concepts am I missing here?
Assuming it is possible, how do I, starting with collections of FOOs and BARs send data back, of course replacing the SyncResponse with something like a SyncUpdateRequest wrapper?

I don't think you'll be able to do this using a set of mappings alone.
Your best option may be to create your mappings for each item and one for the overall structure. The overall mapping just extracts the array as an NSArray of dictionaries. Once you have the array you can iterate over it yourself, check the type and then apply an RKMapperOperation to perform the mappings.
For sending your update request, I'd look at it as a quite separate thing. I'd build an array of dictionaries where the dictionaries have 'plain' key / value pairs for some information and 'complex' key / value pairs for the rows. Your request mapping is then in terms of this array of dictionaries (which cover the custom parts) and the rows (which should be the inverse of your response mapping for the class). Then RestKit should be able to handle it in the standard way (compared to the complexity of your response mapping above).

Related

How to use inheritance with Swift and ObjectMapper?

I'm new to Swift and I have to serialize an object structure into a JSON string in my iOS( iOS >= 8) project.
So I decided to use the ObjectMapper library (I integrated it with Cocoapod).
But my problem is that the structure is the following.
ObjectA can have a list of children objects as an array stored in an instance variable.
Objects that can be stored in the instance array can be of multiple types, say ObjectB and ObjectC. So, in Java with GSON I would have created an InterfaceD and made both of my classes implement it and made the array in ObjectA store InterfaceD types, but I can't figure how to do this with Swift object model as it results in empty {} JSON objects.
The resulting JSON should look like this.
{"children":[
{"type":"ObjectB", "value1":"foo"},
{"type":"ObjectC", "value1":"bar", "value2":"baz"}
]}
and I get
{"children":[
{},
{}
]}
Notice that the two entries that have to be serialized from objectA and ObjectC should have different structures.
I tried multiple things but each times I'm stuck in a dead end.
I tried using generics, tried to use Mappable protocol as my array type, I tried classic class inheritence but any one failed.
Have you any idea how I can achieve this ?
Note that I know that I could add a serialization function to each object and retrieve the strings recursively and concatenate them. But I really want to avoid implementing a JSON serializer by myself as I already use on successfully as Alamofire is already used in the project). Also implementing a new serializer is error prone and not a clean way to solve the problem IMO.
Thanks a lot.
I never had the solution but as a workaround I just made my objects produce a dictionnary from all its values. Then I recursively add child objects dictionnaries as the current dictionnary values.
It adds a toDict() function to each object that I forced with a protocol.
When the resulting object is only made of a tree of dictionnaries, the ObjectMapper serialization works fine...

Swift : How to avoid duplicate entries in CoreData for implementation with JSON array?

I am developing an app in Swift which fetches JSON records from API, converts it into NSArray and reloads in UITableView.
I need to map the NSArray with CoreData and, when making a new request to API, if there is new child added in JSON response, I've to store only that child in CoreData. I.E. I have to avoid repetition of values of NSArray in CoreData.
I found few solution as "using unique constraint for data models" and "HyperSync and DATAStack" but I am not able to do so. Do I have to implement a module to check through all the records ?
If your objects in JSON have some identification, e.g. [ { "id" : 4, ...} ...], then you should store these "id" values in your CoreData objects, and try fetching already existing ones during mapping before creating new ones.
If there is no identification or unique fields in JSON objects, then your task is not resolvable.
E.g. RestKit framework does all that for you automatically, you have to configure only mapping and identificationAttributes.

RestKit POSTed managed object becomes duplicate when response is enveloped in an array

When I POST a Core Data managed object using RestKit, RestKit doesn't update the existing object but creates a new object instead.
The returned JSON always contains the newly created object, but wraps it into a plural keyed array. I found that if I change this to just the one object, the updating works as expected. However, I would like to keep the array in the response so that all responses are consistently in the plural form.
Is there any way I can make RestKit update the record, even when returned from the server wrapped in an array?
Possible solution: identificationAttribute?
On my entities I have an identificationAttribute called remoteID. This is the primary unique key of the record. This will be 0 before the POST, because the object is not yet on the server. I thought that by adding a second identificationAttribute called insertionID, setting that before the POST, and then returning it in the response, would allow RK to find the existing entity in the local store. Alas, it didn't work.
What did work however, was setting the remoteID before the POST, to the next auto increment value on the server! What could explain that it works with remoteID, but not with a second insertionID?
Example request
{
"user": {
"email": "example#example.com"
}
}
Response
{
"users": [{
"email": "example#example.com"
}]
}
I would like to keep the array in the response so that all responses are consistently in the plural form.
You shouldn't, because this is an individual request and response, not a composite.
Your idea about identificationAttribute is correct, but doesn't apply when the response is an array. The array is the trigger (or one of the possible triggers) to abandon the match with the source object and create new objects. Changing this would be hard.
Without knowing more about your real situation, 2 alternatives:
Change the JSON
POST a dictionary instead of the real object and then you won't have a duplicate
When you use multiple identification attributes, all must match for the destination object to be found.
Take care - don't create multiple mappings for the same entity with different identification attributes or you will most likely be debugging the lookup cache for a long time trying to work out what's happening...
If the identity matches before the request is made then the array isn't an issue. To explain the above in more detail:
When you POST an object, RestKit expects to get that object back. So, if you POST one object and get an array back it doesn't know what to do, because it can't map an array into an object. So, it tries to lookup based on the identification attribute (if they exist). If the POSTed object didn't have an id and the returned object does then it will never match. If you set it before POSTing then it will match.

IOS: store a json with array and object nested

I have a question about creating a database with core data.
In my app at first start I should parse some json to obtain some data to insert in core data db.
my json files are structured in this way: (I show only an element of my json)
[{"id":"s1",
"n":"Name hotel",
"id_loc":["l1","l2","l3","l4"],
"val":3,
"tel1":"12345678",
"tel2":"12345678",
"obj":
{"id":"o1",
"n":"Name",
"des":"description",
"flag":"red"}
}]
I understand that I can consider this as an entity in coredata and consider all element as attribute, it's clear.
Now you can see that inside my json there is an array "id_loc" and an object (or dictionary) "obj".
In core data what's the way to manage these two elements?
I suppose that "obj" can be managed as a new entity, and "id_loc", what's the way to set it in my core data DB?
Can you help me?
Thanks
For obj, it's as you suggest: create a new entity, and set up a relationship between the two entities.
For id_loc it depends on how you need to use the data.
If you just want to have that data available when you look up an instance (that is, you maybe display this data but don't ned to search for it), you can store the strings in an NSArray. Make the attribute transformable in the Core Data model editor, and Core Data will read/write the complete array.
If you need to look up data based on id_loc values (for example: Find every object where id_loc contains l3), the best approach is to create another entity to hold values of id_loc, and set up a to-many relationship to that new entity.

RestKit: Map 2-Dimensional Array (Collection in Collection)

I was just trying to parse a JSON-Object which includes a 2-dimensional array.
Example:
{
"2dimarray": [
[{"key": "val"}, {"key": "val"}],
[{"key": "val"}, {"key": "val"}]
]
}
Assuming the contents of 2dimarray[x][y] are only of one type, I added the mapping:
[objectMapping mapKeyPath:#"2dimarray" toRelationship:#"2dimarray" withMapping: myMappingForIncludedObjects];
In the log RestKit tells me:
W restkit.object_mapping:RKObjectMappingOperation.m:438 WARNING: Detected a relationship mapping for a collection containing another collection. This is probably not what you want. Consider using a KVC collection operator (such as #unionOfArrays) to flatten your mappable collection.
But actually it is what I want. Basicly I assumed that the object mapper would fill my Objective-C property NSArray* 2dimarray with NSArray*s that include objects that are mapped with myMappingForIncludedObjects. Instead, each array is mapped (which fails, of course) with myMappingForIncludedObjects.
What am I doing wrong? Or better: What do I need to do to archive the behavior I expected?
I believe that the issue you cite is Blake explaining the problem, not a solution. I don't think RestKit is set up to handle the mapping that you describe (an array of arrays of objects). You can walk through an example of what he describes in the issue as well as looking at his commit, and you'll see that the introduced logic was aimed at detecting the problem and logging it for debugging purposes.

Resources