问题描述
演示
- (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
属性上添加我自己的观察者,并且它们按预期运行良好.
I was doing some experiments with my custom NSOperation subclasses - I was trying to add my own observers on isFinished
property and they worked well as expected.
这些实验让我惊讶于 NSOperation 如何根据对 isFinished
属性变化的观察来调用它的 completionBlocks
-
These experiments made me suprised about how NSOperation calls its completionBlocks
based on its observation of isFinished
property changes -
我不明白这就是为什么这个问题是我的 isFinished
属性的观察者永远不会干扰 NSOperation 的观察者(如果我添加它们,删除它们...),这样 observe isFinished ->当它变为 YES 时调用 completionBlock
逻辑封装得很好,让我可以自由地进行额外的 KVO 观察而不会出现任何问题:
The thing I don't understand and that's why this question is that mine observers of isFinished
property never interfere with NSOperation's ones (if I add them, remove them...), so that the observe isFinished -> invoke completionBlock when it becomes YES
logic is encapsulated pretty well giving me a freedom to do additional KVO observing without any problems:
1) 我做了一些测试,显示 NSOperation 在其 -[NSOperation init]
中对属性变化观察做了某种神奇的订阅 - 我不知道 是什么正在那里进行,但我确保它与isFinished->completionBlock"正在那里有关.我想知道除了常见的 -[NSObject init] 逻辑之外还做了什么?
1) I did a couple of tests showing me that NSOperation does some kind of magic subscription to property changes observation right in its -[NSOperation init]
- I don't know what is going on there but I have ensured that it is something related to "isFinished->completionBlock" is going there. I wonder what is done there besides common -[NSObject init] logic?
2) NSLog 输出显示它不是 NSOperation 类,而是使用 observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:
调用了一些神秘的 NSOperationInternal,最终调用了completionBlock.
2) The NSLog output shows that it is not the NSOperation class but some mysterious NSOperationInternal is called with observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:
that finally invokes completionBlock.
3) 就我的深入理解而言,NSOperation 的 GNUStep 实现在实现细节上有所不同(至少在描述的 isFinished-completionBlock
方面,例如,参见 _finish 方法),这就是为什么我不能用它来帮助理解 Apple 的 NSOperation 方法写了.
3) As far as deep my understanding can spread, the GNUStep implementation of NSOperation differs in implementation details (at least in the described isFinished-completionBlock
aspect, see, for example, _finish method), that is why I can't use it as a helper to understand the Apple's approach to how NSOperation is written.
注意
我没有什么问题没有解决,我只是想在isFinished观察方面更深入地了解NSOperation内部是如何工作的->完成块调用
.
I don't have any problems unsolved, I just want to have a deeper understanding of how NSOperation works internally in the aspect of isFinished observing -> completionBlock invocation
.
我不想看到:Apple 的内部是隐藏的,非 Apple 工程师不可能知道".我想看到一个确实包含对这个主题的深刻见解的答案.
I don't want to see: "Apple's internals are hidden, it is impossible to be known by non-Apple engineers". I want to see an answer that does contain a deep insight into this topic.
推荐答案
这是我目前对 NSOperation 生命周期的了解,虽然不多,但足以回答我最初的问题:
This is what I currently know about NSOperation's lifecycle, it is not much but is pretty enough to answer my original question:
NSOperation 在其 -init 方法中注册对其
isFinished
属性的 KVO 观察.这意味着即使我从未运行过-start
(main
) 方法(我用自定义 NSOperation 子类做了一些实验来确定),也会注册观察.对应的注销是在 NSOperation 的-dealloc
方法中完成的(我无法证明,但它确实是唯一可能发生的地方).
NSOperation registers KVO observation of its
isFinished
property in its -init method. It means that the observation is registered even if I don't ever run-start
(main
) method (I did some experiments with custom NSOperation subclass to determine that). Corresponding un-registration is done in NSOperation's-dealloc
method (I can't prove that, but it is really the only place where it can happen).
为了使 KVO 成为可能和私有",NSOperation 有一些内部容器类 NSOperationInternal,它封装了 NSOperation 自己的 KVO 例程,当我想为我的 NSOperation 类的自定义子类的实例.在我的自定义 NSOperation 子类中,我可以使用我自己的 observeValueForKeyPath:ofObject:change:context:
方法实现,而不必担心与 NSOperation 自己的 KVO 可能发生冲突,因为它不会干扰在 NSOperationInternal 中实现的这个方法.
To make KVO possible and "private" NSOperation has some internal container class NSOperationInternal which encapsulates NSOperation's own KVO routines giving me a freedom to do my custom KVO when I want implement it for the instances of my custom subclasses of NSOperation class. In my custom NSOperation subclasses I can use my own implementation of observeValueForKeyPath:ofObject:change:context:
method without worrying about any possible conflicts with NSOperation's own KVO because it would not interfere with this method implemented in NSOperationInternal.
P.S. 关于魔法"这个词——我知道幕后全是 KVO——所以这里关于 KVO 本身并不奇怪.令我惊讶的是 KVO 如何在具体细节中应用于 NSOperation:这里没有什么神奇之处,但并不是很明显,当我第一次开始引入我自己的 KVO 并怀疑可能的干扰时.
P.S. Regarding the word 'magic' - I know it is all KVO behind the curtains - so no surprises here about KVO itself. My surprises are how KVO is applied to NSOperation in concrete details: nothing magical is here, but it was not really obvious, when I first began introducing my own KVO and became suspicious about possible interference.
这篇关于NSOperation 内部的魔力 - 它如何观察 isFinished 键以便始终运行 completionBlock?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!