3

示范

- (void)test_NSOperationCallsCompletionBlockWhenFinished {
    __block BOOL flag = NO;

    NSOperation *operation = [NSOperation new];

    operation.completionBlock = ^{
        NSLog(@"Hunting NSOperation internals: %@", [NSThread callStackSymbols]);

        flag = YES;
    };

    [operation start];

    while (flag == NO); 

    STAssertTrue(flag, nil);
}

给我以下输入:

2013-07-28 19:59:44.690 SACompositeOperationsApp[99551:3103] Hunting NSOperation internals: (
0   SACompositeOperationsApp            0x000000010005bbd9 __68-[SAOperationTests test_NSOperationCallsCompletionBlockWhenFinished]_block_invoke + 41
1   Foundation                          0x00007fff8a27bb25 __+[__NSOperationInternal _observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:]_block_invoke_3 + 55
2   libdispatch.dylib                   0x00007fff8abd9a82 _dispatch_call_block_and_release + 18
3   libdispatch.dylib                   0x00007fff8abdb083 _dispatch_async_f_redirect_invoke + 112
4   libdispatch.dylib                   0x00007fff8abda961 _dispatch_worker_thread2 + 255
5   libsystem_c.dylib                   0x00007fff91ce13da _pthread_wqthread + 316
6   libsystem_c.dylib                   0x00007fff91ce2b85 start_wqthread + 13
)

背景

我正在用我的自定义 NSOperation 子类做一些实验——我试图在isFinished属性上添加我自己的观察者,它们按预期工作得很好。

这些实验让我惊讶于 NSOperation 如何completionBlocks根据其对isFinished属性变化的观察来调用它 -

我不明白的事情,这就是为什么这个问题是我的isFinished财产观察者永远不会干扰 NSOperation 的观察者(如果我添加它们,删除它们......),所以observe isFinished -> invoke completionBlock when it becomes YES逻辑被很好地封装给我一个自由去做额外的 KVO 观察没有任何问题:

1)我做了一些测试,向我展示了 NSOperation 对属性更改观察进行了某种魔术订阅-[NSOperation init]- 我不知道那里发生了什么,但我确保它与“isFinished->完成块”去那里。我想知道除了常见的 -[NSObject init] 逻辑之外还做了什么?

2) NSLog 输出显示它不是 NSOperation 类,而是调用了一些神秘的 NSOperationInternal observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:,最终调用了completionBlock。

3) 就我的理解而言, NSOperation 的 GNUStep 实现在实现细节上有所不同(至少在所描述的isFinished-completionBlock方面,例如,参见_finish 方法),这就是为什么我不能将它用作帮助了解 Apple 编写 NSOperation 的方法。


注意

我没有任何未解决的问题,我只是想更深入地了解 NSOperation 在isFinished observing -> completionBlock invocation.

我不想看到:“苹果的内部是隐藏的,不可能被非苹果工程师知道”。我想看到一个包含对该主题的深刻见解的答案。

4

1 回答 1

1

这是我目前对 NSOperation 生命周期的了解,虽然不多,但足以回答我最初的问题:

  1. isFinishedNSOperation在其 -init 方法中注册其属性的 KVO 观察。这意味着即使我从未运行-start( main) 方法,观察也会被注册(我使用自定义 NSOperation 子类进行了一些实验来确定这一点)。相应的取消注册是在 NSOperation 的-dealloc方法中完成的(我无法证明这一点,但它确实是唯一可能发生的地方)。

  2. 为了使 KVO 成为可能和“私有”,NSOperation 有一些内部容器类 NSOperationInternal 封装了 NSOperation自己的 KVO 例程,当我想为 NSOperation 类的自定义子类的实例实现它时,我可以自由地执行我的自定义 KVO。在我的自定义 NSOperation 子类中,我可以使用我自己的observeValueForKeyPath:ofObject:change:context:方法实现,而不必担心与 NSOperation 自己的 KVO 有任何可能的冲突,因为它不会干扰在 NSOperationInternal 中实现的这个方法。

PS关于“魔法”这个词——我知道这都是幕后的 KVO——所以这里对 KVO 本身并不感到意外。让我惊讶的是 KVO 如何在具体细节上应用到 NSOperation:这里没有什么神奇的东西,但是当我第一次开始引入我自己的 KVO 并对可能的干扰产生怀疑时,这并不是很明显。

于 2013-11-05T21:25:39.313 回答