0

我正在查看此线程中的一些代码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 中的完成块将保留参数以便释放块是安全的吗?

4

3 回答 3

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:...保留它。因此,在 期间,该块是有效的,因为它仍然由. 在块执行期间,它仍然有效(因为它仍然在执行的内部)。如果它是异步的,则必须保留其参数。等等。runBlockperformSelector:...runBlockdoSomethingAsynchronouslyWithCompletionBlock

但你不需要那样看。仔细想一想,你就会意识到,内存管理规则是这样制定的,这样你就不用担心其他代码做了什么,只管本地需要什么

内存管理规则归结为以下条件:每个函数/方法都期望其参数在被调用时有效(这通常意味着在函数调用的持续时间内,因为调用函数在此期间不会运行,所以如何它会变得无效吗,除非这个函数做了一些间接删除它的事情(比如从字典中删除)?);并且对函数调用后它将保持有效多长时间没有任何期望。而已。一切由此而来。

例如,在您的 中doWork,您只关心需要使用该块多长时间。由于之后不需要它performSelector:...,您可以安全地释放它。performSelector:...异步处理它并不重要;您甚至可能不知道它是异步的(例如,您可能正在选择一个未知的方法来动态调用)。关键是,它做什么并不重要。为什么?因为performSelector:...不假定参数比您调用它时更有效。因此,如果它需要保留更长时间(确实如此),它必须保留它(但您不需要知道这一点)。只要它需要它,它就会保留它。

同样,runBlock可以假设它给出的参数在其调用期间是有效的。由于它不需要保留它更长时间(它所做的只是调用块),它不需要保留它。该块不会改变这一点。为什么?同样,由于块不假定其参数(包括块本身)在其调用后是有效的,所以runBlock不需要保证它。如果块调用doSomethingAsynchronouslyWithCompletionBlock,那很好。doSomethingAsynchronouslyWithCompletionBlock不假设任何东西在它的调用之外是有效的,所以如果它是真正异步的,它必须在某个地方保留它。等等

于 2012-06-08T21:21:52.803 回答
1

您可以在调用后立即释放它-performSelector:withObject:afterDelay:。(我假设您打算使用 after-delay 变体。)像往常一样,您负责内存管理,其他代码负责其内存管理。这是另一种说法,-performSelector:withObject:afterDelay:必须保留接收者和传入的对象,直到执行选择器之后。

编辑添加:顺便说一句,您为什么不dispatch_after()按照您链接到的问题的答案中的说明使用?

于 2012-06-08T00:11:13.093 回答
-2

我可能只是尝试使用参数传递一个数组。

于 2012-06-08T00:22:04.507 回答