当完成块成功时,NSOperationQueue添加新操作

时间:2015-06-03 17:56:52

标签: ios objective-c grand-central-dispatch nsoperationqueue

我正在尝试在后台线程上按顺序完成一些操作。

我调用的函数已经有一个完成块,所以当函数完成时我想用一个新参数调用相同的函数。

所以基本上是连续的操作。

dispatch_asyncDISPATCH_QUEUE_SERIAL以正确的顺序触发函数,但在调用下一个函数之前不关心第一个函数是否完成,所以我不想使用它们。

NSOperationQueue* serialQ = [[NSOperationQueue alloc] init]; serialQ.maxConcurrentOperationCount = 1;对我更有意义。因此,当第一个函数开始计算队列上的第二个函数时,必须等到它完成完成块。

NSOperationQueue* serialQ = [[NSOperationQueue alloc] init];
    serialQ.maxConcurrentOperationCount = 1; //this will set this queue to Serial



        for (File *file in queueArrray) {
            Streamer *streamer=[[Streamer alloc] init];

            NSBlockOperation *downloadOperation = [[NSBlockOperation alloc] init];

            __weak NSBlockOperation *weakDownloadOperation = downloadOperation;

            [weakDownloadOperation addExecutionBlock:^{
                [streamer loadFile:file withCallback:^(NSString *error, BOOL success) {
                    if (success) {
                        NSLog(@"file loaded %@",file.fileUrl);
                        //here start the next operation !!!!!!!!
                        ??????????????????????????????????????
                    }
                }];
            }];  
        }

3 个答案:

答案 0 :(得分:3)

串行队列infact确保添加到要执行的队列的第一个块在第二个块执行之前完成。

-(void)testSerialQueue
{
    dispatch_queue_t serialQueue = dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);

    dispatch_async(serialQueue, ^{
        [self countTo100];
    });

    dispatch_async(serialQueue, ^{
        [self countFrom200To400];
    });

    dispatch_async(serialQueue, ^{
        [self countFrom400To500];
    });

}

- (void)countTo100
{
    for (int i = 0; i < 100; i++) {
        NSLog(@"%d", i);
    }
}

- (void)countFrom200To400
{
    for (int i = 200; i < 400; i++) {
        NSLog(@"%d", i);
    }
}

- (void)countFrom400To500
{
    for (int i = 400; i < 500; i++) {
        NSLog(@"%d", i);
    }
}

如果从上面查看日志,它将首先从0 .. 100打印,然后从200 .. 400和400 .. 500打印。

现在,请考虑以下代码段,您可以在其中执行并发块中的每个方法,例如

-(void)testSerialQueue
{
    dispatch_queue_t serialQueue = dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);

    dispatch_async(serialQueue, ^{
        [self countTo100];
    });

    dispatch_async(serialQueue, ^{
        [self countFrom200To400];
    });

    dispatch_async(serialQueue, ^{
        [self countFrom400To500];
    });

}

- (void)countTo100
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(concurrentQueue, ^{
        for (int i = 0; i < 100; i++) {
            NSLog(@"%d", i);
        }
    });

}

- (void)countFrom200To400
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(concurrentQueue, ^{
        for (int i = 200; i < 400; i++) {
            NSLog(@"%d", i);
        }
    });
}

- (void)countFrom400To500
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(concurrentQueue, ^{
        for (int i = 400; i < 500; i++) {
            NSLog(@"%d", i);
        }
    });
}

这里,您在串行队列中添加了所有方法,但方法本身在并发块中运行。因此,在这种情况下,结果是随机的。你也可以使用像这样的dispatch_group序列化它,

-(void)testSerialQueue
{
    dispatch_queue_t serialQueue = dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);

    self.group = dispatch_group_create();

    dispatch_async(serialQueue, ^{
        [self countTo100];
    });

    dispatch_async(serialQueue, ^{
        [self countFrom200To400];

    });

    dispatch_async(serialQueue, ^{
        [self countFrom400To500];
    });
}

- (void)countTo100
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(self.group);

    dispatch_async(concurrentQueue, ^{
        for (int i = 0; i < 100; i++) {
            NSLog(@"%d", i);
        }
        dispatch_group_leave(self.group);
    });
    dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}

- (void)countFrom200To400
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(self.group);

    dispatch_async(concurrentQueue, ^{
        for (int i = 200; i < 400; i++) {
            NSLog(@"%d", i);
        }
        dispatch_group_leave(self.group);
    });
    dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);

}

- (void)countFrom400To500
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(self.group);

    dispatch_async(concurrentQueue, ^{
        for (int i = 400; i < 500; i++) {
            NSLog(@"%d", i);
        }
        dispatch_group_leave(self.group);

    });
    dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);

}

在这里,您将再次看到它按顺序打印日志。因此,dispatch_group用于序列化并发操作。您可能希望此时在serialQueue中删除dispatch_async。

现在,操作队列,让我们看一下简单的例子,

-(void)testSerialQueue
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.maxConcurrentOperationCount = 1;

    NSBlockOperation *operation1 = [[NSBlockOperation alloc] init];
    NSBlockOperation *operation2 = [[NSBlockOperation alloc] init];
    NSBlockOperation *operation3 = [[NSBlockOperation alloc] init];

    [operation1 addExecutionBlock:^{
        [self countTo100];
    }];

    [operation2 addExecutionBlock:^{
        [self countFrom200To400];
    }];

    [operation3 addExecutionBlock:^{
        [self countFrom400To500];
    }];        
}

- (void)countTo100
{
    for (int i = 0; i < 100; i++) {
        NSLog(@"%d", i);
    }
}

- (void)countFrom200To400
{
    for (int i = 200; i < 400; i++) {
        NSLog(@"%d", i);
    }
}

- (void)countFrom400To500
{
    for (int i = 400; i < 500; i++) {
        NSLog(@"%d", i);
    }
}

计数方法被添加到NSOperationQueue中,maxConcurrentOperation为&#39; 1&#39;现在更像是一个串行队列。每个方法都不会产生一些其他队列,因此,计数在同一个串行队列上执行。所以,它们都是有序打印的。

现在,让我们看一个模拟你案例的例子。

-(void)testSerialQueue
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.maxConcurrentOperationCount = 1;

    NSBlockOperation *operation1 = [[NSBlockOperation alloc] init];
    NSBlockOperation *operation2 = [[NSBlockOperation alloc] init];
    NSBlockOperation *operation3 = [[NSBlockOperation alloc] init];

    [operation1 addExecutionBlock:^{
        [self countTo100];
    }];

    [operation2 addExecutionBlock:^{
        [self countFrom200To400];
    }];

    [operation3 addExecutionBlock:^{
        [self countFrom400To500];
    }];        
}

- (void)countTo100
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(concurrentQueue, ^{
        for (int i = 0; i < 100; i++) {
            NSLog(@"%d", i);
        }
    });

}

- (void)countFrom200To400
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(concurrentQueue, ^{
        for (int i = 200; i < 400; i++) {
            NSLog(@"%d", i);
        }
    });
}

- (void)countFrom400To500
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(concurrentQueue, ^{
        for (int i = 400; i < 500; i++) {
            NSLog(@"%d", i);
        }
    });
}

在此用例中,您将操作添加到NSOperationQueue(即一个串行队列),但同样,各个方法在其他一些并发队列中运行。因此,执行顺序非常随机。现在,您可以像使用串行队列一样使用dispatch_group来解决这个问题。

-(void)testSerialQueue
{
    self.group = dispatch_group_create();

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.maxConcurrentOperationCount = 1;

    NSBlockOperation *operation1 = [[NSBlockOperation alloc] init];
    NSBlockOperation *operation2 = [[NSBlockOperation alloc] init];
    NSBlockOperation *operation3 = [[NSBlockOperation alloc] init];

    [operation1 addExecutionBlock:^{
        [self countTo100];
    }];

    [operation2 addExecutionBlock:^{
        [self countFrom200To400];
    }];

    [operation3 addExecutionBlock:^{
        [self countFrom400To500];
    }];        
}

- (void)countTo100
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(self.group);

    dispatch_async(concurrentQueue, ^{
        for (int i = 0; i < 100; i++) {
            NSLog(@"%d", i);
        }
        dispatch_group_leave(self.group);
    });
    dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}

- (void)countFrom200To400
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(self.group);

    dispatch_async(concurrentQueue, ^{
        for (int i = 200; i < 400; i++) {
            NSLog(@"%d", i);
        }
        dispatch_group_leave(self.group);
    });
    dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);

}

- (void)countFrom400To500
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(self.group);

    dispatch_async(concurrentQueue, ^{
        for (int i = 400; i < 500; i++) {
            NSLog(@"%d", i);
        }
        dispatch_group_leave(self.group);

    });
    dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);

}

现在,您将看到计数再次有序。这是因为dispatch_group等待每个异步任务完成。

对于您的特定用例,您可以使用循环来调用某些方法,像这样创建NSInvocationOperation,

-(void)testSerialQueue
{
    self.group = dispatch_group_create();

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.maxConcurrentOperationCount = 1;


    NSArray *selectors = @[@"countTo100", @"countFrom200To400", @"countFrom400To500"];

    for (NSString *selector in selectors) {
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
                                                                                selector:NSSelectorFromString(selector)
                                                                                  object:nil];
        [queue addOperation:operation];
    }

}

- (void)countTo100
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(self.group);

    dispatch_async(concurrentQueue, ^{
        for (int i = 0; i < 100; i++) {
            NSLog(@"%d", i);
        }
        dispatch_group_leave(self.group);
    });
    dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}

- (void)countFrom200To400
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(self.group);

    dispatch_async(concurrentQueue, ^{
        for (int i = 200; i < 400; i++) {
            NSLog(@"%d", i);
        }
        dispatch_group_leave(self.group);
    });
    dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);

}

- (void)countFrom400To500
{
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(self.group);

    dispatch_async(concurrentQueue, ^{
        for (int i = 400; i < 500; i++) {
            NSLog(@"%d", i);
        }
        dispatch_group_leave(self.group);

    });
    dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);

}

答案 1 :(得分:1)

您的目标方法是异步的。这意味着您不能使用普通块操作,您需要创建一个自定义操作子类,以便在异步方法完成之前操作不会完成。

在google中搜索为示例创建异步操作子类的示例,因为您需要组织一些事项。

或者你可以拥有类似文件数组(或其他类似内容),每次异步方法完成后检查是否有任何文件,删除第一个项目并进行处理。这将持续到阵列为空......

答案 2 :(得分:0)

您可以使用信号量等待功能完成,如果成功再次使用参数调用它。