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

Ruu*_*uug 2 memory-management objective-c

一个简单的程序:

-(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]);

}
Run Code Online (Sandbox Code Playgroud)

输出:

self rc=1

self rc=2

i'm done

self rc=2
Run Code Online (Sandbox Code Playgroud)

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

nac*_*o4d 13

- [NSObject performSelector:withObject:afterDelay:inModes:]文档:

2013/11/01答案

正如预期的那样,文档似乎更新了,现在他们并没有说目标对象被保留,但他们仍然提到了runloop中的预定计时器.

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

上面的文档并没有提到" 保留 "一词,但并不意味着目标不会被保留.

这是我在模拟器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
Run Code Online (Sandbox Code Playgroud)

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


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

此方法保留接收器和anArgument参数,直到执行选择器.

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

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

希望能帮助到你