示范
- (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-> completionBlock”正在那里有关。我想知道除了常见的那样做了什么 - [NSObject init]逻辑?
2)NSLog输出显示它不是NSOperation类,但是使用observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:
调用一些神秘的NSOperationInternal,最终调用completionBlock。
3)就我的理解能够深入传播而言,GNUStep implementation of NSOperation在实现细节上有所不同(至少在所描述的isFinished-completionBlock
方面,例如,参见_finish method),这就是为什么我不能用它来帮助理解苹果公司编写NSOperation的方法。
N.B。
我没有任何未解决的问题,我只想更深入地了解NSOperation如何在isFinished observing -> completionBlock invocation
方面内部工作。
我不想看到:“Apple的内部隐藏,非苹果工程师不可能知道”。我希望看到一个答案,其中包含对此主题的深入了解。
答案 0 :(得分:1)
这就是我目前对NSOperation生命周期的了解,它并不多,但足以回答我原来的问题:
NSOperation在其-init方法中注册KVO对其isFinished
属性的观察。这意味着即使我没有运行-start
(main
)方法,也会注册观察(我使用自定义NSOperation子类进行了一些实验来确定)。相应的取消注册是在NSOperation的-dealloc
方法中完成的(我不能证明这一点,但它确实是唯一可以发生这种情况的地方)。
为了使KVO成为可能而且“私有”NSOperation有一些内部容器类NSOperationInternal,它封装了NSOperation的自己的KVO例程,当我想为它实现它时,我可以自由地进行自定义KVO我的自定义NSOperation类的子类的实例。在我的自定义NSOperation子类中,我可以使用我自己的observeValueForKeyPath:ofObject:change:context:
方法实现,而不必担心与NSOperation自己的KVO有任何可能的冲突,因为它不会干扰NSOperationInternal中实现的这种方法。
P.S。关于“魔术”这个词 - 我知道幕后都是KVO - 因此KVO本身并不令人惊讶。我的惊喜是KVO如何应用于NSOperation的具体细节:这里没什么神奇之处,但当我第一次开始介绍我自己的KVO并对可能的干扰产生怀疑时,这并不是很明显。