我正在查看此帖子How do you trigger a block after a delay, like -performSelector:withObject:afterDelay:?中的一些代码。我想知道,如果块以异步方式执行某些操作,块何时应该被释放?
假设我的代码看起来像这样:
- (void)testMethod:(id)parameter
{
dispatch_block_t block = ^{
SomeAsyncTask *t = [SomeAsyncTask withCompletionBlock:^{
[parameter doAction];
}];
};
[self performSelector:@selector(executeBlock:)
onThread:backgroundThread
withObject:block
waitUntilDone:NO];
dispatch_release(block); //I can release the block here because performSelector retains the block
}
- (void)executeBlock:(id)block
{
block();
}
那么关键是,SomeASyncTask中的完成块会保留参数,以便释放块是安全的吗?
答案 0 :(得分:2)
Ken Thomases的回答是正确的。我想对你的评论作出更详细的回应。
首先,目前尚不清楚您的意思是performSelector:withObject:
还是performSelector:withObject:afterDelay:
,因为performSelector:withObject:
是直接同步通话,因此[self performSelector:@selector(runBlock:) withObject:block_];
与[self runBlock:block_]
相同。我假设它是performSelector:withObject:afterDelay:
,因为performSelector:withObject:
不那么有趣。
一步一步地看。 performSelector:withObject:afterDelay:
保留其参数,因此您可以在给出块之后释放它。 performSelector:...
保留通过其选择器的效果。因此,在runBlock
期间,该块有效,因为它仍由performSelector:...
保留。在执行块期间,它仍然有效(因为它仍在执行runBlock
内)。 doSomethingAsynchronouslyWithCompletionBlock
必须保留其参数,如果它是异步的。等等。
但你不需要那样看待它。一旦你仔细思考,你就会意识到内存管理规则是这样做的,所以你不需要担心其他代码的作用,只需要担心本地需要的内容。
内存管理规则归结为以下条件:每个函数/方法都要求其参数在被调用时有效(这通常意味着在函数调用的持续时间内,因为调用函数在这段时间内没有运行,所以它怎么会变得无效,除非这个函数做了间接删除它的东西(比如从字典中删除)?); 并且对函数调用后保持有效的时间没有任何期望。而已。一切都从此开始。
例如,在doWork
中,您只关心需要多长时间才能使用该块。由于您在performSelector:...
之后不需要它,因此您可以安全地释放它。 performSelector:...
可以异步地对它做什么并不重要;您可能甚至不知道它是异步的(例如,您可能选择一种未知的方法来动态调用)。关键是,它的作用无关紧要。为什么?因为performSelector:...
不认为参数有效的时间比调用时更长。因此,如果它需要保持更长时间(并且确实如此),它必须保留它(但您不需要知道这一点)。并且只要需要它就会保留它。
类似地,runBlock
可以假设它给出的参数在其调用期间有效。因为它不需要保持更长时间(它只是调用块),所以它不需要保留它。该块不会改变这一点。为什么?同样,因为块没有假设它的参数(包括块本身)在调用后是有效的,所以runBlock
不需要保证它。如果块调用doSomethingAsynchronouslyWithCompletionBlock
,那很好。 doSomethingAsynchronouslyWithCompletionBlock
并不认为除了调用之外任何东西都是有效的,所以如果它真的是异步的,它必须将它保留在某个地方。等
答案 1 :(得分:1)
您可以在调用-performSelector:withObject:afterDelay:
后立即将其释放。 (我假设您打算使用延迟后变体。)像往常一样,您负责内存管理,其他代码负责其内存管理。这是另一种说法-performSelector:withObject:afterDelay:
必须保留接收者和传入的对象直到执行选择器之后的另一种方式。
编辑添加:顺便说一下,为什么不使用dispatch_after()
,如您所链接问题的答案中所示?
答案 2 :(得分:-2)
我可能只是尝试使用参数传递数组。