我正在尝试建立一个非常复杂的RestKit操作链。首先,我必须向父对象列表发出请求(让我们称之为parentRequestOperation),对于列表中的每个父对象,我必须创建另一个请求操作来获取相关对象(让我们称之为childRequestOperation)。显然我只能在parentRequestOperation的success()块中创建childRequestOperations,因为我之前不知道我应该创建多少以及我应该创建它们的详细信息。
我想在所有操作完成后得到一些反馈。为此我用我的处理块创建了一个NSOperation实例(让我们称之为finishedOperation),向它添加了对parentRequest的依赖,并添加到我的RKObjectManager的operationQueue中。
我的问题是如何在childRequestOperations和finishedOperation之间进行“会合”。我在创建childRequestOperation之后尝试将对childRequestOperation的依赖项添加到finishedOperation(仍然在parentRequestOperation的成功块中)。但问题是RestKit在与RKObjectManager的operationQueue不同的调度队列中异步调用成功块,所以一旦parentRequestOperation完成,在我可以向childRequestOperation添加新的依赖项之前触发finishedOperation。
在类似场景中设置finishedOperation的最佳做法是什么?
答案 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];