我正在查看此线程中的一些代码 如何在延迟后触发块,例如 -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 中的完成块将保留参数,以便安全地释放该块?
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
不假定任何内容在其调用之外都是有效的,因此如果它确实是异步的,则必须将其保留在某个地方。等。
您可以在调用 -performSelector:withObject:afterDelay:
后立即释放它。(我假设你的意思是使用延迟后的变体。像往常一样,您负责内存管理,其他代码负责其内存管理。这是另一种说法,-performSelector:withObject:afterDelay:
必须保留接收器和传入的对象,直到执行选择器之后。
编辑添加:顺便说一下,你为什么不使用你所链接的问题的答案中所示的dispatch_after()
?
我可能会尝试传递带有参数的数组。