RestKit/RestKit — pull request #2076 by carllindberg (2014-11-03 17:49:36+00:00)
Title: Speed up getting a target object

The code in RKMappingOperation which gets the "representation" object ready for the data source's targetObject method is expensive.

```
NSDictionary *dictionaryRepresentation = [representation isKindOfClass:[NSDictionary class]] ? representation : @{ [NSNull null] : representation };
NSDictionary *metadata = RKDictionaryByMergingDictionaryWithDictionary(self.metadata, @{ @"mapping": @{ @"parentObject": (self.destinationObject ?: [NSNull null]) } });
RKMappingSourceObject *sourceObject = [[RKMappingSourceObject alloc] initWithObject:dictionaryRepresentation parentObject:parentRepresentation rootObject:self.rootSourceObject metadata:metadata];
```

This argument is completely ignored in a non-CoreData situation, so there is no real need to create these objects in that case. To avoid this expense, add a new data source method which is the same except without the representation argument, in case the data source can respond without it. If it cannot, we fall back to the previous behavior. Even CoreData situations can be helped if there is a non-RKEntityMapping mapping involved.

Timings before:
(Device) Mapping 5000 students with relationship mapping: 31.493391
(Simulator) Mapping 5000 students with relationship mapping: 4.373885

and after:
(Device) Mapping 5000 students with relationship mapping: 28.091627
(Simulator) Mapping 5000 students with relationship mapping: 3.926955

It does seem a little kludgy to add a data source method for what amounts to a coding detail, but the performance gain is pretty large and hard to ignore. If there is another way to fix the performance, that would be good.

Another option would be to re-use the existing data source method but just pass "nil" as a representation object, and if returns nil then obtain the representation and call it again. That would require changes to existing implementations and would not be passive.

A pretty good chunk of the cost here (roughly 60% of it from memory) is the merging dictionaries function. If that cost is eliminated in other ways (see upcoming pull request) then the effect of this change is not as much. However, it is still significant.