与RestKit操作会合

时间:2013-10-01 16:15:24

标签: ios restkit grand-central-dispatch nsoperation

我正在尝试建立一个非常复杂的RestKit操作链。首先,我必须向父对象列表发出请求(让我们称之为parentRequestOperation),对于列表中的每个父对象,我必须创建另一个请求操作来获取相关对象(让我们称之为childRequestOperation)。显然我只能在parentRequestOperation的success()块中创建childRequestOperations,因为我之前不知道我应该创建多少以及我应该创建它们的详细信息。

我想在所有操作完成后得到一些反馈。为此我用我的处理块创建了一个NSOperation实例(让我们称之为finishedOperation),向它添加了对parentRequest的依赖,并添加到我的RKObjectManager的operationQueue中。

我的问题是如何在childRequestOperations和finishedOperation之间进行“会合”。我在创建childRequestOperation之后尝试将对childRequestOperation的依赖项添加到finishedOperation(仍然在parentRequestOperation的成功块中)。但问题是RestKit在与RKObjectManager的operationQueue不同的调度队列中异步调用成功块,所以一旦parentRequestOperation完成,在我可以向childRequestOperation添加新的依赖项之前触发finishedOperation。

在类似场景中设置finishedOperation的最佳做法是什么?

2 个答案:

答案 0 :(得分:1)

您可以查看为要使用的操作设置successCallbackQueue,并在执行现有相关操作时将您自己的任务推送到同一队列。如果您使用的队列是串行的,那么您可以保证执行的顺序。

答案 1 :(得分:0)

最后,我提出了一个稍微开箱即用的解决方案。它是一个使用资源计数器信号量扩展的NSObject子类。仅当信号量达到零时才执行此操作。

<强> SemaphoreDependencyOperation.h

@interface SemaphoreDependencyOperation : NSOperation

@property (atomic, readonly) int32_t dependencySemaphore;

-(void)incrementDependencySemaphore;
-(void)decrementDependencySemaphore;

@end

<强> SemaphoreDependencyOperation.m

#import "SemaphoreDependencyOperation.h"
#include <libkern/OSAtomic.h>

@implementation SemaphoreDependencyOperation

-(void)incrementDependencySemaphore
{
    [self willChangeValueForKey:@"dependencySemaphore"];
    OSAtomicIncrement32(&_dependencySemaphore);
    [self didChangeValueForKey:@"dependencySemaphore"];
}

-(void)decrementDependencySemaphore
{
    [self willChangeValueForKey:@"dependencySemaphore"];
    OSAtomicDecrement32(&_dependencySemaphore);
    [self didChangeValueForKey:@"dependencySemaphore"];
}

+(NSSet *)keyPathsForValuesAffectingIsReady
{
    return [NSSet setWithObject:@"dependencySemaphore"];
}

-(BOOL)isReady
{
    return [super isReady] && _dependencySemaphore <= 0;
}

@end

用法:

SemaphoreDependencyOperation* trackerOperation = [[UpdateTrackerOperation alloc] init];
[trackerOperation setCompletionBlock:^{
    NSLog(@"Everything done"); 
}];

NSURLRequest* parentRequest = // ...
RKObjectRequestOperation* parentRequestOperation =
  [self.objectManager objectRequestOperationWithRequest:parentRequest
                                                success:
  ^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) 
  {
    // create childRequestOperations based on mappingResult
    for (MyObject* myObject in [mappingResult array]) 
    {
       NSURLRequest* childRequest = // ... create it from myObject
       RKObjectRequestOperation* childRequestOperation = 
         [self.objectManager objectRequestOperationWithRequest:parentRequest
                                                       success:
         ^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) 
         {
           // ...
           [trackerOperation decrementDependencySemaphore];
         }
                                                       failure:nil];

         [self.objectManager enqueueObjectRequestOperation:childRequestOperation];
         [trackerOperation incrementDependencySemaphore];
    }
    [trackerOperation decrementDependencySemaphore];
  }
                                                failure:nil];

[self.objectManager enqueueObjectRequestOperation:parentRequestOperation];
[trackerOperation incrementDependencySemaphore];
[self.objectManager.operationQueue addOperation:trackerOperation];