对performSelector的保留计数的影响:withObject:afterDelay:inModes

时间:2010-12-11 01:33:13

标签: objective-c memory-management

一个简单的程序:

-(void)doSomething {

 NSLog(@"self rc=%d", [self retainCount]);

 [self performSelector:@selector(doMe:) withObject:nil afterDelay:0 inModes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];

 NSLog(@"self rc=%d", [self retainCount]);
}

-(void)doMe:(id)object {

 NSLog(@"i'm done");

 NSLog(@"self rc=%d", [self retainCount]);

}

输出:

self rc=1

self rc=2

i'm done

self rc=2

为什么保留计数增加到并保持在2?

2 个答案:

答案 0 :(得分:13)

来自-[NSObject performSelector:withObject:afterDelay:inModes:] documentation

2013/11/01回答

文档看起来像预期的那样更新,现在他们并没有说目标对象被保留,但他们仍然提到了runloop中的预定计时器。

如果使用NSTimer,则该对象必须由某人保留,否则将无法保证可以执行选择器,因为没有人可以确保该对象仍然存活。如果不使用ARC的weak,它将崩溃。 在我看来,Apple编辑其文档时没有提到实现细节,尽管我认为这很明显。

上面的文档根本没有提到 retain 这个词,但这并不意味着不保留目标。

这是我在模拟器iOS7.0中的调试器中尝试过的:

(lldb) p (int)[self retainCount]
(int) $1 = 8
(lldb) expr (void)[self performSelector:@selector(description) withObject:nil afterDelay:1.0]
(lldb) p (int)[self retainCount]
(int) $2 = 9
(lldb) expr (void)[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(description) object:nil]
(lldb) p (int)[self retainCount]
(int) $3 = 8

结论:保留了对象,但这不是我们应该关心的。 先生解决了:p


上一个答案:(仍然有效)

  

此方法保留接收器和   之前的anArgument参数   执行选择器。

因为如果没有保留该对象,该对象可能会在执行之前被释放,并且您的应用程序将崩溃。

设置并尝试使用NSTimers触发方法时的逻辑是相同的。如果目标对象不再存在(已释放),则实际触发计时器时,您的应用程序将崩溃。所以performSelector:withObject:afterDelay:...和它的朋友们在这里让我们的生活变得更轻松,因为它确保应用程序在计时器被触发时不会崩溃;)

希望有所帮助

答案 1 :(得分:4)

您似乎错误地认为doMe:中的NSLog将在doSomething:中的第二个之前执行。那是错的。即使延迟为0,performSelector:afterDelay:…方法仍然使用runloop计划消息,因此它将在下一次runloop迭代时执行。

除此之外,几乎没有理由去查看对象的保留计数 - 如果你看的话,不要相信你所看到的。 retainCount方法的结果充其量是混乱而最糟糕的是直接欺骗 - 对于一个显而易见且非常常见的例子,保留计数并不反映自动释放。