学习NSBlockOperation

学习NSBlockOperation

本文介绍了学习NSBlockOperation的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是块的忠实粉丝,但没有将它们用于并发。经过一些谷歌搜索,我拼凑了这个想法,以隐藏我在一个地方学到的一切。目标是在后台执行一个块,当它完成时,执行另一个块(如UIView动画)......

I'm a big fan of blocks, but have not used them for concurrency. After some googling, I pieced together this idea to hide everything I learned in one place. The goal is to execute a block in the background, and when it's finished, execute another block (like UIView animation)...

- (NSOperation *)executeBlock:(void (^)(void))block completion:(void (^)(BOOL finished))completion {

    NSOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:block];

    NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
        completion(blockOperation.isFinished);
    }];

    [completionOperation addDependency:blockOperation];
    [[NSOperationQueue mainQueue] addOperation:completionOperation];

    NSOperationQueue *backgroundOperationQueue = [[NSOperationQueue alloc] init];
    [backgroundOperationQueue addOperation:blockOperation];

    return blockOperation;
}

- (void)testIt {

    NSMutableString *string = [NSMutableString stringWithString:@"tea"];
    NSString *otherString = @"for";

    NSOperation *operation = [self executeBlock:^{
        NSString *yetAnother = @"two";
        [string appendFormat:@" %@ %@", otherString, yetAnother];
    } completion:^(BOOL finished) {
        // this logs "tea for two"
        NSLog(@"%@", string);
    }];

    NSLog(@"keep this operation so we can cancel it: %@", operation);
}

我的问题是:


  1. 当我运行它时它会起作用,但我错过了什么......隐藏的地雷?我没有测试取消(因为我没有发明长时间的操作),但看起来它会起作用吗?

  2. 我担心我需要限定我的声明backgroundOperation使我可以在完成块中引用它。编译器没有抱怨,但是有没有潜伏的保留周期?

  3. 如果字符串是一个ivar,如果我的键值在块时观察到它会发生什么运行?或者在主线程上设置一个计时器并定期记录它?我能看到进展吗?我会将它声明为原子吗?

  4. 如果这样可以正常工作,那么它似乎是一种隐藏所有细节并获得并发性的好方法。 Apple为什么不为我写这个?我错过了重要的事情吗?

  1. It works when I run it, but am I missing anything ... hidden land mine? I haven't tested cancellation (because I haven't invented a long operation), but does that look like it will work?
  2. I'm concerned that I need to qualify my declaration of backgroundOperation so that I can refer to it in the completion block. The compiler doesn't complain, but is there a retain cycle lurking there?
  3. If the "string" were an ivar, what would happen if I key-value observed it while the block was running? Or setup a timer on the main thread and periodically logged it? Would I be able to see progress? Would I declare it atomic?
  4. If this works as I expect, then it seems like a good way to hide all the details and get concurrency. Why didn't Apple write this for me? Am I missing something important?

谢谢。

推荐答案

我不是NSOperation或NSOperationQueues的专家,但我认为下面的代码有点好,虽然我认为它仍有一些警告。可能已经足够用于某些目的但不是并发的一般解决方案:

I am not an expert in NSOperation or NSOperationQueues but I think below code is a bit better although I think it has some caveats still. Probably enough for some purposes but is not a general solution for concurrency:

- (NSOperation *)executeBlock:(void (^)(void))block
                      inQueue:(NSOperationQueue *)queue
                   completion:(void (^)(BOOL finished))completion
{
    NSOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:block];
    NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
        completion(blockOperation.isFinished);
    }];
    [completionOperation addDependency:blockOperation];

    [[NSOperationQueue currentQueue] addOperation:completionOperation];
    [queue addOperation:blockOperation];
    return blockOperation;
}

现在让我们使用它:

- (void)tryIt
{
    // Create and configure the queue to enqueue your operations
    backgroundOperationQueue = [[NSOperationQueue alloc] init];

    // Prepare needed data to use in the operation
    NSMutableString *string = [NSMutableString stringWithString:@"tea"];
    NSString *otherString = @"for";

    // Create and enqueue an operation using the previous method
    NSOperation *operation = [self executeBlock:^{
        NSString *yetAnother = @"two";
        [string appendFormat:@" %@ %@", otherString, yetAnother];
    }
    inQueue:backgroundOperationQueue
    completion:^(BOOL finished) {
        // this logs "tea for two"
        NSLog(@"%@", string);
    }];

    // Keep the operation for later uses
    // Later uses include cancellation ...
    [operation cancel];
}

您的问题的一些答案:


  1. 取消。通常你是NSOperation的子类,所以你可以检查 self.isCancelled 并提前返回。请参阅,这是一个很好的例子。在当前示例中,您无法检查是否已从您提供的块中取消操作以生成 NSBlockOperation ,因为此时尚未执行此类操作。在调用块时,取消 NSBlockOperation 显然是可行的,但。 NSBlockOperation s适用于特定的简单案例。如果您需要取消,您可以更好地继承 NSOperation :)

  1. Cancelation. Usually you subclass NSOperation so you can check self.isCancelled and return earlier. See this thread, it is a good example. In current example you cannot check if the operation has being cancelled from the block you are supplying to make an NSBlockOperation because at that time there is no such an operation yet. Cancelling NSBlockOperations while the block is being invoked is apparently possible but cumbersome. NSBlockOperations are for specific easy cases. If you need cancellation you are better subclassing NSOperation :)

我在这里看不到问题。虽然注意两件事。 a)我改变方法do以在当前队列中运行完成块b)需要队列作为参数。正如@Mike Weller所说,你应该更好地提供后台队列,这样你就不需要为每个操作创建一个,并且可以选择用来运行你的东西的队列:)

I don't see a problem here. Although note two things. a)I changed the method do to run the completion block in current queue b)a queue is required as a parameter. As @Mike Weller said, you should better supply background queue so you don't need to create one per each operation and can choose what queue to use to run your stuff :)

我想是的,你应该让字符串 atomic 。你不应该忘记的一件事是,如果你向队列提供了几个操作,它们可能不会按顺序运行(必然),所以你最终可能会在字符串中找到一条非常奇怪的消息。如果你需要连续一次运行一个操作,你可以在开始排队操作之前执行: [backgroundOperation setMaxConcurrentOperationCount:1];
在但是:

I think yes, you should make string atomic. One thing you should not forget is that if you supply several operations to the queue they might not run in that order (necessarily) so you could end up with a very strange message in your string. If you need to run one operation at a time serially you can do: [backgroundOperation setMaxConcurrentOperationCount:1]; before start enqueuing your operations.There is a reading-worthy note in the docs though:


  • 我认为阅读完这些行后你知道:)

  • I think after reading these lines you know :)

    这篇关于学习NSBlockOperation的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

  • 08-05 23:17