0

I have the following JSON body containing arrays of decimal numbers within arrays:

( I. )

{
"decimals":
  [
     [
        18000.00,
        18000.00
     ]
  ],
} 

I have created a class DecimalEntity with helper attribute "number" (NSDecimalNumber) and recursive relationship "numbers" (1-many relationship). Also this variant is possible:

( II. )

 {
    "decimals":
         [
            18000.00,
            18000.00
         ],
    }

How can I setup the mapping of the DecimalEntity so that it parses the above JSON bodies? I have setup the property mapping for "number" which works for (II.) but it does not work for (I.) That is why I've created the relationship between the DecimalEntity and "numbers" using

RKPropertyMapping* decimalEntityPropertyMapping =
                              [RKRelationshipMapping relationshipMappingFromKeyPath:nil
                                                                          toKeyPath:@"numbers"
                                                                        withMapping:decimalEntityMapping];

and added this decimalEntityPropertyMapping back in decimalEntityMapping to create a recursive relationship:

[decimalEntityMapping                        addPropertyMapping:decimalEntityPropertyMapping];

But this variant crashes with **[NSNull hasPrefix:]: unrecognized selector sent to instance**

Also I tried to flatten the arrays using @unionOfArrays but I do not know how to use it. [mapping addAttributeMappingsFromDictionary:@{@"@unionOfArrays": @"numbers" }]; ?

Thank you for a hint.

UPDATE:

I'm trying to do it in a conventional way, because it should work I think. I have changed the structure and the relationship of my classes (NSManagedObject subclasses):

DecimalEntityArray: contains a helper relationship 1-M to DecimalEntity's:"decimals"

DecimalEntity: contains a helper attribute of the type Decimal: "number"

The class DecimalEntityArray is mapped to the outer brackets and the DecimalEntity to inner brackets:

"arrayOfArrays":
  [ >>>>> 1-M, DecimalEntityArray
     [ >>>>> 1-M, DecimalEntity
        18000.00,
        18000.00
     ]
  ],

Mapping setup looks like this:

// setting up the attribute mappings:
RKObjectMapping* decimalEntityMapping               = 
    [DecimalEntity mappingForStore:managedObjectStore];
RKObjectMapping* decimalEntityArrayMapping          = 
    [DecimalEntityArray mappingForStore:managedObjectStore];

// the **nil** value denotes the fact that there is no dictionary, 
// just a direct mapping to NSSet of DecimalEntity's  
RKPropertyMapping* decimalEntityPropertyMapping =
              [RKRelationshipMapping relationshipMappingFromKeyPath:nil
                                                          toKeyPath:@"decimals"
                                                        withMapping:decimalEntityMapping];

// setup the relationship between DecimalEntityArray and its DecimalEntity's 
[decimalEntityArrayMapping   addPropertyMapping:decimalEntityPropertyMapping];


// finally setup the relation between the outermost json attribute, "arrayOfArrays" 
// and DecimalEntityArray
RKPropertyMapping* decimalEntityArrayPropertyMappingPotentialWin =
    [RKRelationshipMapping relationshipMappingFromKeyPath:@"potentionalWin"
                                                toKeyPath:@"potentionalWin"
                                              withMapping:decimalEntityArrayMapping];

But this solution crashes with [NSNull hasPrefix:]: unrecognized selector sent to instance and a suggestion

Mapping one to many relationship value at keyPath 'arrayOfArrays' to 'arrayOfArrays' ... 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.

This is probably not what you want. But that is really what I want. So this conventional way does not work? I guess I am a step from getting it correct.

[NSNull hasPrefix:]: unrecognized selector sent to instance originates from the definition of decimalEntityPropertyMapping, where the KeyPath == nil. The strange thing is the nil value is allowed according the documentation:

sourceKeyPath:
A key path from which to retrieve data in the source object representation that is to be mapped as a relationship. If nil, then the mapping is performed directly against the parent object representation.

Vladimír Slavík
  • 1,727
  • 1
  • 21
  • 31
  • Do you have control of the source JSON? Have you looked at using a dynamic mapping? – Wain Jun 09 '14 at 08:45
  • Thank you Wain. No I can not change the way it is being sent to the client. (although I do my best to push the change because every client has to do some sort of trickery to parse it at the moment, but chance the api will change is really small). I am considering using a proxy object which would parse the host array and it would contain a 1-M relationship to DecimalNumber/or a new class containing decimal number. I will check the dynamic mapping http://restkit.org/api/latest/Classes/RKDynamicMapping.html – Vladimír Slavík Jun 09 '14 at 09:20
  • Dynamic mapping should help, possibly also with a collection operator like `@unionOfArrays` when you find an array of arrays. – Wain Jun 09 '14 at 11:38
  • I have updated the question with my rogue solution. It works. Interestingly without side effects. What about to add a new meta property @self which would direct the mapping engine to map directly the unnamed json field to the relationshop? – Vladimír Slavík Jun 11 '14 at 08:08
  • Add your solution as an answer so you can accept it. The @self question is better asked as a github issue. – Wain Jun 11 '14 at 13:44

1 Answers1

0

SOLUTION

I have checked the issue with debugger (adding symbolic exception with the symbol -[NSObject doesNotRecognizeSelector:]) and added the line if([keyPath isKindOfClass:[NSNull class]]) return YES; in RKMappingOperation.m and it works smoothly with the above mapping defined:

// Returns YES if there is a value present for at least one key path in the given collection
static BOOL RKObjectContainsValueForKeyPaths(id representation, NSArray *keyPaths)
{
    for (NSString *keyPath in keyPaths) {
        if([keyPath isKindOfClass:[NSNull class]]) return YES;
        if ([representation valueForKeyPath:keyPath]) return YES;
    }
    return NO;
}
Vladimír Slavík
  • 1,727
  • 1
  • 21
  • 31