2

I am using AFNetworking in this example but I think it pertains more to NSOperation. I have two operations, once is dependent on the other finishing. However op2 really shouldn't run until op1's success block has completely run. In the case of dependencies in an operation queue, op2 will run as soon as op1 is done, but before op1's success block is done.

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSURLRequest *request = [manager.requestSerializer requestWithMethod:@"GET" URLString:url parameters: nil error: nil];
NSOperation *op1 = [http.manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id userLocations) {
   NSLog(@"Success");
   // do some stuff 

   // more stuf

   // I am done, ready for the next operation.
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
   NSLog(@"Error: %@", error);
}];
NSOperation* op2 = // create op, this will depend on op1 finishing
[op2 addDependency:Op1];  // op2 is dependent on op1 finishing

[manager.operationQueue addOperations:@[op1, op2] waitUntilFinished:NO];

This does not quite work for me as op2 is dependent on some things that are set in op1's success block. Meaning op2 cannot start until op1 is done with its success block.

Is there a way with NSOperations to queue them such that each can wait until the blocks are done running as well? If not how can I re-design tho accomplish this dependency.

lostintranslation
  • 23,756
  • 50
  • 159
  • 262
  • Could you use a dispatch semaphore? https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW24 – Paulw11 Aug 23 '14 at 01:35
  • Does this answer help? http://stackoverflow.com/questions/13762406/nsoperation-forcing-an-operation-to-wait-others-dynamically – goodgoogleymoogley Aug 23 '14 at 02:22
  • Dispatch is possible. Did not know about that, thanks I will take a look and see if I can solve my problem that way. – lostintranslation Aug 23 '14 at 19:21

2 Answers2

1

I would structure things a bit differently, setting up the second operation within the first. Like this:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSURLRequest *request = [manager.requestSerializer requestWithMethod:@"GET" URLString:url parameters: nil error: nil];
NSOperation *op1 = [manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id userLocations) {
    NSLog(@"Success");
    // do some stuff

    // more stuf

    // I am done, ready for the next operation.
    // SO put the other operation here!
    NSOperation* op2 = // create op, this will depend on op1 finishing

    [manager.operationQueue addOperation:op2];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];
[manager.operationQueue addOperation:op1];
HalR
  • 11,411
  • 5
  • 48
  • 80
  • That is a great answer for this simple case. What if I said now that op2 and op3 both depend on op1. And op4 depends on op2. Code becomes more complex because starting Ops is done in a bunch of success blocks all over the place. Would be nice to define a true dependency on ops which is not meet until the completion block is in fact done. – lostintranslation Aug 23 '14 at 19:20
  • I think at that point you are better off using NSNotificationCenter. Here is a good description: http://stackoverflow.com/a/2191802/793607 – HalR Aug 23 '14 at 19:55
0

I run in to the same problem and found out an excellent solution with just using [operationQueue setSuspended:YES] please see the second answer in this post: NSOperation wait until asynchronous block executes

jd11
  • 71
  • 5
  • In this scenario, it's probably easier to just call the second operation from within the continuation (the completion block) - than to use the built-in "dependency feature". Also ensure, that you call the second operation from the correct thread - as most Operation subclasses have thread confinement. That is, dispatch explicitly (mostly to the main thread). This "dependency" feature is actually more difficult to use correctly and more error prone, than it seems to be - and I've rarely seen implementations (and subclasses of Operations) that do this correctly thread-safe. – CouchDeveloper Jun 08 '19 at 19:17