user-44651
user-44651

Reputation: 4124

NSBlockOperation is not waiting on dependency before executing

I am learning NSOperations & NSOperationQueue.

I have a set of NSBlockOperation: "UPLOAD" & "DELETE". Delete MUST wait for Upload to finish before executing.

What I would like to happen is for one operation set to complete before moving on to the next set.

I have used NSThread sleepForTimeInterval to simulate the upload waiting and deletion latency times.

However the operations are not waiting for the set to complete.

I set maxConcurrentOperationCount to 1 but that doesn't seem to work.

You can see from the output that Set 1 finished fine.

But in set two Upload 3 stared before the Delete 2 was finished. Then Upload/Delete 4 is fine. Then from there it starts to mix up a lot more.

Any help?

OUTPUT:

Start UPLOAD 1
Completed UPLOAD 1
Start DELETE 1
Completed DELETE 1

Start UPLOAD 2
Completed UPLOAD 2
Start DELETE 2
Start UPLOAD 3
Completed DELETE 2
Start DELETE 3
Completed UPLOAD 3
Completed DELETE 3

Start UPLOAD 4
Start DELETE 4
Completed UPLOAD 4
Completed DELETE 4

Start UPLOAD 5
Start DELETE 5
Completed UPLOAD 5
Start UPLOAD 6
Completed DELETE 5
Start DELETE 6
Completed UPLOAD 6
Start UPLOAD 7
Completed DELETE 6

CODE:

- (void)viewDidLoad {
    [super viewDidLoad];


    NSOperationQueue *operationQueue = [NSOperationQueue mainQueue];
    operationQueue.maxConcurrentOperationCount = 1;


//pretend there are 100 images that need to be uploaded and information in a SQLite DB waiting to be deleted upon successful upload of the image.

//Upload 1 image at a time, upon successful upload, delete the respective DB info then move to the next image 
    for (__block int i = 1; i < 100; i++){
        NSOperation * UPLOAD = [self createNewOperationWithInt:i Message:@"UPLOAD"];
        NSOperation * DELETE = [self createNewOperationWithInt:i Message:@"DELETE"];
        [DELETE addDependency:UPLOAD];
        [operationQueue addOperation:UPLOAD];
        [operationQueue addOperation:DELETE];

    }

}

- (NSBlockOperation *) createNewOperationWithInt:(int)i Message:(NSString*)message {
    NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"Start %@ %i",message , i);

        if ([message containsString:@"UPLOAD"]) {
             [NSThread sleepForTimeInterval:1]; //Pretend there is Network latency on upload
        }

        if ([message containsString:@"DELETE"]) {
            [NSThread sleepForTimeInterval:0.5]; //Pretend the SQLDB is being accessed
        }

    }];
    operation.queuePriority = NSOperationQueuePriorityNormal;
    operation.qualityOfService  = NSOperationQualityOfServiceUtility;
    operation.completionBlock = ^{
       NSLog(@"Completed %@ %i",message , i);
    };

    return operation;
}

Upvotes: 2

Views: 606

Answers (1)

Marcos Crispino
Marcos Crispino

Reputation: 8218

This behavior seems to be fine. The "problem" is that both the completion block and the dependency run after the completion of the upload task. That's why you sometimes get the "Start DELETE N+1" before the "Completed UPLOAD N".

Try adding a message at the end of the block operation, to check that it finishes before starting the next one:

NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"Start %@ %i",message , i);

    if ([message containsString:@"UPLOAD"]) {
         [NSThread sleepForTimeInterval:1]; //Pretend there is Network latency on upload
    }

    if ([message containsString:@"DELETE"]) {
        [NSThread sleepForTimeInterval:0.5]; //Pretend the SQLDB is being accessed
    }

    NSLog(@"Finished %@ %i",message , i);
}];

Upvotes: 3

Related Questions