RestKit/RestKit — pull request #1764 by sadlerjw (2014-01-24 22:41:22+00:00)
Title: Use a property to store RKObjectRequestOperation on RKHTTPRequestOperation

This allows consumers of RestKit to pay attention to NSNotifications sent by AFNetworking and find out which RKObjectRequestOperation they correspond to.

For instance, I have a table view whose data source is backed by a collection of data objects that are fetched from the server via RestKit. In order to simplify table view cell insertions/deletions/reloads, I use KVO. The `observeValueForKeyPath:ofObjectchange:context:` implementation calls the appropriate `insertRowsAtIndexPaths:withRowAnimation:`/`deleteRowsAtIndexPAths:withRowAnimation:` invocations as the values of properties are changed by RestKit's mapping engine.

In order to have consistent animations, I make all of these invocations inside a `startUpdates`/`endUpdates` pair. This means that `startUpdates` needs to be called before RestKit performs any mapping, and `endUpdates` is called after RestKit completes all mapping. Calling `endUpdates` is easy since I can do it from the `success`/`failure` blocks passed into `putObject:path:parameters:success:failure:`. Calling `startUpdates` at the correct time requires listening to `AFNetworkingOperationDidFinishNotification` since it's sent before RestKit performs mapping.

The `object` attached to this `NSNotification` is an `RKHTTPRequestOperation`, but in order to know how to treat the notification, the code consuming this notification needs to know what the owning `RKObjectRequestOperation` instance is, in order to check whether the `targetObject` matches the expected object.

Some sample code (modified and simplified - in my real code, I'm not passing a `UITableView` into a model method :wink:)

```objc
// MyBaseModelClass.m

- (void)putObjectAffectingTableView:(UITableView)tableView {
__weak THRModel* weakSelf = self;
__block id observer = nil;

// We want to call [tableView beginUpdates] right before RestKit does its mapping
observer = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingOperationDidFinishNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
if (weakSelf == nil) {
[[NSNotificationCenter defaultCenter] removeObserver:observer];
return;
}

if ([note.object isKindOfClass:RKHTTPRequestOperation.class]) {
RKHTTPRequestOperation* http = (RKHTTPRequestOperation*)note.object;
RKObjectRequestOperation* op = http.objectRequestOperation;

// The request that this notification is about ...
// is it the one that we were sending when we created this observer?
if (op && op.targetObject == weakSelf) {
[tableView beginUpdates]
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}
}
}];

[objectManager putObject:self path:[self.url stringByAppendingString:@".json"]
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
[tableView endUpdates]
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
[tableView endUpdates]
}];
}
```