TestObj
类是一个简单的类,它有一个方法doSomethingInBackground
,我在其中发送performSelectorInBackground
方法,让自己在后台线程中休眠5秒。
@implementation TestObj
- (void)dealloc
{
NSLog(@"%@, is main thread %u", NSStringFromSelector(_cmd), [NSThread isMainThread]) ;
}
- (void)doSomethingInBackground
{
[self performSelectorInBackground:@selector(backgroundWork) withObject:nil] ;
}
- (void)backgroundWork
{
sleep(5) ;
}
@end
我分配并初始化实例并发送doSomethingInBackground
消息并为其分配nil
,以便尽快释放它。
TestObj *obj = [[TestObj alloc] init] ;
[obj doSomethingInBackground] ;
obj = nil ;
我发现dealloc
将在约5秒obj = nil;
后运行,系统似乎在向self
方法[self performSelectorInBackground:@selector(backgroundWork) withObject:nil] ;
发送backgroundWork
之后{{1}}返回后,实例将被释放。
任何人都可以告诉我系统背后的工作。感谢。
答案 0 :(得分:2)
-[NSObject performSelectorInBackground:withObject:]
调用-[NSThread initWithTarget:selector:object:]
,它会保留原始接收者(此处作为target
参数传递)
NSThread文档:"在执行分离线程期间保留对象target和argument。它们在线程最终退出时被释放。"
答案 1 :(得分:2)
来自文档,
performSelectorInBackground:withObject:
方法创建一个新的分离线程,并使用指定的方法作为新线程的入口点。例如,如果你有一个对象(由变量myObj表示)并且该对象有一个你想在后台线程中运行的doSomething方法,你可以使用以下代码来做到这一点:
[myObj performSelectorInBackground:@selector(doSomething) withObject:nil];
调用此方法的效果与使用当前对象,选择器和参数对象作为参数调用detachNewThreadSelector:toTarget:withObject:
NSThread
方法的效果相同。使用默认配置立即生成新线程并开始运行。
在detachNewThreadSelector中:toTarget:withObject:documentation,
执行期间保留对象aTarget和anArgument 分离的线程,然后释放。退出已分离的线程 aTarget完成后立即(使用exit类方法) 执行aSelector方法。
关于performSelector:AfterDelay:,
此方法设置一个计时器来执行aSelector消息 当前线程的运行循环。计时器配置为在。中运行 默认模式(NSDefaultRunLoopMode)。当计时器触发时,线程 尝试从运行循环中取消消息并执行 选择。如果运行循环正在运行并且在默认情况下,它会成功 模式;否则,计时器等待直到运行循环处于默认状态 模式
并且
计时器保持对该对象的强引用,直到它为止 计时器)无效。
如果您不希望保留Obj,可以使用弱引用对象
TestObj *obj = [[TestObj alloc] init] ;
__weak typeof(obj) weakObj = obj;
[weakObj doSomethingInBackground] ;
obj = nil ;
答案 2 :(得分:1)
虽然在其他答案中已经讨论过像performSelector:
这样的特殊情况,但我认为将答案添加到一般情况中是有帮助的:
向其发送消息时会自我保留
没有。在两个手动保留计数和ARC self
中永远不会隐式保留。在方法执行期间,必须注意不要释放消息的接收者。
虽然ARC self
的类型很强,但实际上并未保留该对象。请参阅ARC documentation。