I extend NSOperation (call it A) which contains NSOperationQueue for other NSOperations (which is another extended class different from A, call these operations B). When operation A is running (executing B operations) how do i call a specific function/method on operation A when certain event takes place on B operations? For example every operation B that finishes it calls a function on operation A returning itself?
*Nested NSOperation and NSOperationQueue(s)
Hope this mockup pseudo code can help to draw the picture.
//My classes extended from NSOperation
NSOperation ClassA
NSOperation ClassB
//MainApp
-(void)applicationDidFinishLaunching:(NSNotification *)aNotification {
ClassA A1;
ClassA A2;
NSOperationQueue Queue;
开发者_开发问答 Queue AddOperation: A1;
Queue AddOperation: A2;
}
//Main of ClassA
-(void)main {
ClassB B1;
ClassB B2;
NSOperationQueue Queue;
Queue AddOperation: B1;
Queue AddOperation: B2;
}
//Main of ClassB
-(void)main {
//Do some work and when done call selector on ClassA above
}
NSOperation
has a mechanism to register dependencies. See NSOperation's documentation and addDependency:
.
Let's split the work your A
does: AX
: spawning B
s, and AY
: collecting the data in B
.
I think it's better to design B
so that it can be used without A
. Let B
just download the data and hold it in the property data
, as in
@interface B:NSOperation{
}
-initWithURL:(NSURL*)url atPosition:(NSUInteger)position;
@property (readonly)NSData* data;
@end;
A
doesn't have to have its own queue, one per object. Generating B
's doesn't take much time either,
so AX
doesn't have to be an operation.
So, I would just define the operations AY
and B
, prepare just one queue, and perform something like
NSOperationQueue* queue=...;
NSArray* urls = ... ;
for(NSURL* url in urls){
AY* ay=[[AY alloc] init];
for(chunks in url){
B* b= an instance for B for the chunk in url
[ay addDependency:b];
[queue addOperation:b];
}
[queue addOperation:ay];
}
Then, in AY
's main, you can
-main{
NSArray*bs=[self dependencies];
for(B*b in bs){
NSData* data=b.data;
}
}
Note that, thanks to the dependencies, it's guaranteed that when AY
is run, all of the B
's has finished its operation.
This way, the implementation of B
is independent of A
.
I've written a class called MXSuperOperation to nest NSOperations for the app I'm currently working on. I've posted it here:
https://gist.github.com/joerick/e4d2c99a2127715d9bc3
Subclass MXSuperOperation and add suboperations in the -mainError: method.
@interface OperationA : MXSuperOperation
@end
@implementation OperationA
- (BOOL)mainError:(NSError **)error
{
[self addSuboperation:[OperationB new]];
[self addSuboperation:[OperationB new]];
return YES;
}
@end
Then to run something at the end of all the OperationB
s, you can either add a completionBlock to operationA:
[operationA setCompletionBlockWithSuccess:^(id operation) {
NSLog(@"success");
} failure:^(id operation, NSError *error) {
NSLog(@"error %@", error);
}];
Or you can implement -endError:
in OperationA (depending on how you want to structure the code).
Note that this class is built on an NSOperation subclass I made called MXCheckedOperation, which just codifies success/failure and error reporting for NSOperations.
精彩评论