1

我有一组要处理的对象。对象具有如下方法

@interface CustomObject : NSObject

- (void)processWithCompletionBlock:(void (^)(BOOL success))completionBlock;

@end

每个对象的处理需要不同的时间,并且可能有不同的结果。并且已知处理本身是同时执行的。说实话,限制并发操作的数量会很棒,因为它们非常密集。

所以我需要枚举这个对象数组并处理它们。如果某些对象处理失败,我需要跳过所有其余对象。当然,在枚举和处理所有对象之后,我需要得到通知。

是否应该通过创建NSOperationQueueNSOperation子类来解决?这个类如何满足这些要求?还有其他一些优雅的方法吗?

4

3 回答 3

1

这正是NSOperation设计的目的。调度队列是低级得多的处理程序,您必须为此构建许多您需要的部分。你当然可以这样做(NSOperationQueue建立在 GCD 之上),但你会重新发明NSOperation.

在大多数情况下,您可以处理NSOperation两种方式。如果它很简单,您可以创建一个NSBlockOperation. 如果它有点复杂,您可以子类NSOperation化并覆盖该main方法以执行您想要的操作。

有几种方法可以取消所有其他操作。每个组可以有一个单独的操作队列。然后,您可以轻松调用cancelAllOperations以关闭所有内容。或者你可以有一个单独的控制器,它知道相关操作的列表,它可以调用cancel它们。

请记住,“取消”只是意味着“如果它没有盯着,就不要安排,如果有就设置isCancelled。” 它不会中止正在运行的操作。如果要中止正在运行的操作,该操作需要定期检查isCancelled.

您通常应该限制队列将运行的并发操作的数量。使用setMaximimumConcurrentOperationCount:.

有两种方法可以确定所有操作都已完成。您可以进行额外的操作(通常是 a BlockOperation)并使用addDependency:使其依赖于所有其他操作。这是一个很好的异步解决方案。如果您可以处理同步解决方案,那么您可以使用waitUntilAllOperationsAreFinished. 我通常更喜欢前者。

于 2012-08-09T00:59:02.797 回答
1

使用 NSOperationQueue 并使您的类成为 NSOperation

使用此方法排队您的工作

- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait

将操作队列的引用添加到您创建的 NSOperation 子类

如果发生错误调用

- (void)setSuspended:(BOOL)suspend

在 NSOperationQueue 上

于 2012-08-09T00:59:07.460 回答
0

好的。为了帮助其他人了解如何处理这种方法,我分享了我自己的代码。

为了限制并发线程的数量,我们可以调用实例的-(void)setMaximimumConcurrentOperationCount:方法。NSOperationQueue

为了迭代对象并提供完成机制,我们可以定义以下方法:

- (void)enumerateObjects:(NSArray *)objects
{
    // define the completion block
    NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"Update UI");
    }];

    // register dependencies
    for (CustomObject *obj in objects) {
        CustomOperation *operation = [[CustomOperation alloc] initWithCustomObject:obj];
        [completionOperation addDependency:operation]; // set dependencies for the completion block
        [_operationQueue addOperation:operation];
    }

    // register completionOperation on main queue to avoid the cancellation
    [[NSOperationQueue mainQueue] addOperation:completionOperation];
}

覆盖子类的- (void)start方法,NSOperation开始我们的自定义操作:

- (void)start
{
    // We need access to the operation queue for canceling other operations if the process fails
    _operationQueue = [NSOperationQueue currentQueue];

    if ([self isCancelled]) {
        // Must move the operation to the finished state if it is canceled.
        [self willChangeValueForKey:@"isFinished"];
        _finished = YES;
        [self didChangeValueForKey:@"isFinished"];
        return;
    }

    [self willChangeValueForKey:@"isExecuting"];
    // We do not need thread detaching because our `-(void)processWithCompletionBlock:` method already uses dispatch_async
    [self main]; // [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
    _executing = YES;
    [self didChangeValueForKey:@"isExecuting"];

}

覆盖子类的- (void)main方法NSOperation来处理我们的自定义对象:

- (void)main
{
    @try {
        NSLog(@"Processing object %@", _customObject);
        [_customObject processWithCompletionBlock:^(BOOL success) {
            _processed = success;
            if (!success) {
                NSLog(@"Cancelling other operations");
                [_operationQueue cancelAllOperations];
            }
            [self completeOperation];
        }];
    }

    @catch (NSException *exception) {
        NSLog(@"Exception raised, %@", exception);
    }
}

感谢@Rob 指出我缺少的部分。

于 2012-08-09T07:02:34.600 回答