【问题标题】:NSOperationQueue add new operation when completion block is successfulNSOperationQueue 在完成块成功时添加新操作
【发布时间】:2015-06-04 04:24:15
【问题描述】:

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

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

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

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 !!!!!!!!
                        ??????????????????????????????????????
                    }
                }];
            }];  
        }

【问题讨论】:

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


    【解决方案1】:

    串行队列实际上确保添加到队列中执行的第一个块在第二个块执行之前完成。

    -(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。

    现在,考虑以下 sn-p,您可以在并发块中执行每个方法,例如,

    -(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);
        }
    }
    

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

    现在,让我们看一个模拟您的案例的示例。

    -(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);
    
    }
    

    【讨论】:

    • 解释得很好。
    【解决方案2】:

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

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

    或者,您可以拥有文件数组(或其他文件)之类的东西,并且每次异步方法完成时检查那里是否有任何内容,删除第一项并处理它。这将一直持续到数组为空...

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-17
        • 1970-01-01
        • 1970-01-01
        • 2011-10-01
        • 2014-09-16
        相关资源
        最近更新 更多