Search code examples
jsonrestkitkey-value-coding

Parsing unnamed JSON arrays within array with Restkit


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.


Solution

  • 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;
    }