3

I am facing some weird results with addOperationWithBlock.

My function looks something like this:

-(void) myFunction{
   NSLog(@"VISITED");

 ..



  for (NSDictionary *Obj in myObjects)
  {
    [operationQueue addOperationWithBlock:^(void){
         MyObject* tmp = [self tediousFunction:Obj];
         // threadTempObjects is member NSMutableArray
         [self.threadTempObjects addObject:tmp];
         NSLog(@"ADDED");
    }];
  }

 [operationQueue addOperationWithBlock:^(void){
       [self.myArray addObjectsFromArray:self.threadTempObjects];

       for(myObject *myObj in self.myArray)
       {
            // MAIN_QUEUE
            [[NSOperationQueue mainQueue] addOperationWithBlock:^(void) {
                [self updateUI:myObj];
            }];
       }
   }];



   [operationQueue addOperationWithBlock:^(void){
       [[NSOperationQueue mainQueue] addOperationWithBlock:^(void) {
             [self filterResults];
       }];
   }];

}

My dictionary contains 4 values, and therefore the ADDED shows in the log 4 times. BUT, when I check inside the filterResults, I see that there are only 2 objects inside myArray. Meaning that the 4 times the operationQueue was called did not end before the filterResults operation was called (although it was added later!)

I thought that the operationQueue is serial and that I can count on it that when I add an operation it would be added right after the last operation. So it is weird that only 2 operations are in the array in the aftermath. What am I missing? Thanks

Ted
  • 3,805
  • 14
  • 56
  • 98
  • 1
    You are using 2 different queues here, please share their configuration code so we may verify they are indeed serial (serial would mean `maxConcurrentOperationCount` of 1) – Dan Shelly Apr 08 '13 at 17:18
  • You might be confusing with [GCD operation queue](http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html). – Dan Shelly Apr 08 '13 at 17:22
  • Your operation queue is only serial if you make it serial. – Tom Harrington Apr 08 '13 at 17:25
  • initialization: operationQueue = [[NSOperationQueue alloc] init]; Is the operation Queue not functioning as a queue ? Do operations happen all together? – Ted Apr 08 '13 at 17:48

1 Answers1

3

From what you shared as your initialisation code we can learn that operationQueue is not serial, meaning it will execute operations, and allocate thread up until the system set maximal thread count (same as with GCD).
This mean that operations added to operationQueue are running in parallel.
To run them serially set the maxConcurrentOperationCount to 1.
Try something like:

__block __weak id weakSelf = self;
[operationQueue setMaxConcurrentOperationCount:1];

for (NSDictionary *Obj in myObjects)
{
    [operationQueue addOperationWithBlock:^{
        MyObject* tmp = [weakSelf tediousFunction:Obj];
        // threadTempObjects is member NSMutableArray
        [weakSelf.threadTempObjects addObject:tmp];
        NSLog(@"ADDED");
    }];
}

[operationQueue addOperationWithBlock:^{
    [weakSelf.myArray addObjectsFromArray:weakSelf.threadTempObjects];

    for(myObject *myObj in weakSelf.myArray)
    {
        // MAIN_QUEUE
        [[NSOperationQueue mainQueue] addOperationWithBlock:^(void) {
            [weakSelf updateUI:myObj];
        }];
        [[NSOperationQueue mainQueue] addOperationWithBlock:^(void) {
            [weakSelf filterResults];
        }];
    }
}];

But, this is equal (or even less efficient) to simply:

__block __weak id weakSelf = self;
[operationQueue addOperationWithBlock:^{
    for (NSDictionary *Obj in myObjects) {
        MyObject* tmp = [weakSelf tediousFunction:Obj];
        // threadTempObjects is member NSMutableArray
        [[NSOperationQueue mainQueue] addOperationWithBlock:^(void) {
            [weakSelf updateUI:tmp];
        }];
        [weakSelf.myArray addObject:tmp];
        NSLog(@"ADDED");
    }
    [[NSOperationQueue mainQueue] addOperationWithBlock:^(void) {
        [weakSelf filterResults];
     }];
}];
Dan Shelly
  • 5,991
  • 2
  • 22
  • 26
  • Hi Dan, in your first example you do this : `operationQueue addOperationWithBlock `. What if in this block we will also have: `operationQueue addOperationWithBlock` (new addOperationWithBlock block), is it ok? I can't find information about that. Or it's better to avoid it and just remove second operation block? – Dima Deplov Jul 29 '15 at 09:46
  • 1
    @flinth This should also work for nested `addOperationWithBlock` – Dan Shelly Jul 29 '15 at 22:36