RestKit/RestKit — Issue #588: Retain cycle with RKManagedObjectMappingOperation
Author: matej
Created: 2012-03-08 12:10:27+00:00
State: open

I've noticed a memory leak, that is caused by a retain cycle between a RKMappingOperationQueue and several RKManagedObjectMappingOperations.

RKManagedObjectMappingOperations hold a strong reference to their queue, which gets established in `- [RKObjectMapper mapFromObject:toObject:atKeyPath:usingMapping:]`. Inside `- [RKManagedObjectMappingOperation connectRelationships]` a block that references `self` is created and added to the queue. This causes a) self to be retained by the block and b) the block being retained by the queue. This forms the problematic retain cycle.

Some additional info from instruments:
Cycles: http://cl.ly/3n1u201m0U0C0e063t29
Queue (depicting the unbalanced retains from operations): http://cl.ly/0Y3n0L2z3Y2f3g301V0a
Operation (unbalanced retains from the block runtime): http://cl.ly/3R2s2s1s0G3Q0q1X0w3J

It is possible to break the retain cycle by using a __bock reference to self inside `- [RKManagedObjectMappingOperation connectRelationships]`.

```objc
- (void)connectRelationships {
if ([self.objectMapping isKindOfClass:[RKManagedObjectMapping class]]) {
NSDictionary* relationshipsAndPrimaryKeyAttributes = [(RKManagedObjectMapping*)self.objectMapping relationshipsAndPrimaryKeyAttributes];
for (NSString* relationshipName in relationshipsAndPrimaryKeyAttributes) {
if (self.queue) {
RKLogTrace(@"Enqueueing relationship connection using operation queue");
__block RKManagedObjectMappingOperation *selfRef = self;
[self.queue addOperationWithBlock:^{
[selfRef connectRelationship:relationshipName];
}];
} else {
[self connectRelationship:relationshipName];
}
}
}
}
```

This should be safe since the operations will stay around until the thread's autorelease pool get's drained when the thread is destroyed (see screenshot #3).