使用 [NSThread detachNewThreadSelector:toTarget:withObject:] 时如何设置自动释放池

Posted

技术标签:

【中文标题】使用 [NSThread detachNewThreadSelector:toTarget:withObject:] 时如何设置自动释放池【英文标题】:How to set up an autorelease pool when using [NSThread detachNewThreadSelector:toTarget:withObject:] 【发布时间】:2011-03-18 09:36:08 【问题描述】:

您好,我正在使用 [NSThread detachNewThreadSelector:toTarget:withObject:] 并且我遇到了很多内存泄漏,因为我没有为分离的线程设置自动释放池。我只是想知道我实际上在哪里做这个?是在我打电话之前吗

[NSThread detachNewThreadSelector:toTarget:withObject:]

还是在另一个线程中正在运行的方法中?

任何帮助将不胜感激,一些示例代码会很棒。

谢谢。

【问题讨论】:

@user636866:在我看来,Simon Lee 的回答是最容易理解和切中要害的。尽管其他人也值得为他们的努力投票。 【参考方案1】:

在你用线程调用的方法中......即给定这个......

[NSThread detachNewThreadSelector:@selector(doStuff) toTarget:self withObject:nil];

你的方法是……

- (void)doStuff 
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  //Do stuff
  [pool release];

【讨论】:

对于 ARC,请参阅 this thread【参考方案2】:

你必须在你调用的方法中设置一个自动释放池,它将在新的分离线程中执行。

例如:

// Create a new thread, to execute the method myMethod
[NSThread detachNewThreadSelector:@selector(myMethod) toTarget:self withObject:nil];

- (void) myMethod 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // Here, add your own code
    // ...

    [pool drain];

请注意,我们在 autoreleasepool 上使用 drain 而不是 release。在 ios 上,它没有区别。在 Mac OS X 上,如果您的应用程序被垃圾回收,它将触发垃圾回收。这使您可以编写可以更轻松地重复使用的代码。

【讨论】:

【参考方案3】:

创建新线程:

[NSThread detachNewThreadSelector:@selector(myMethod) toTarget:self withObject:nil];

创建新线程调用的方法。


- (void)myMethod

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    // Your Code
    [pool release];

如果您需要从新线程内部对主线程执行某些操作(例如,显示加载符号)怎么办?使用 performSelectorOnMainThread。

[self performSelectorOnMainThread:@selector(myMethod) withObject:nil waitUntilDone:false];

参考:-iPhone SDK Examples

【讨论】:

【参考方案4】:

在您调用的方法中执行此操作。本质上,您应该将被调用的方法设置为一个独立的工作单元(事实上,它也将与通过[NSOperation][1] 或Grand Central Dispatch 调用兼容:这两种组织并发工作的更好方法) .

但是如果我无法更改我在新线程上调用的方法的实现怎么办?

在这种情况下,您将不再这样做:

[NSThread detachNewThreadSelector: @selector(blah:) toTarget: obj withObject: arg]

这样做:

[NSThread detachNewThreadSelector: @selector(invokeBlah:) toTarget: self withObject: dict]

- (void)invokeBlah: (id)dict 
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  id obj = [dict objectForKey: @"target"];
  id arg = [dict objectForKey: @"argument"];
  [obj blah: arg];
  [pool release];

您也可以创建一个封装远程对象调用的NSInvocation,而不是使用字典。我只是选择了一本字典,因为它是在 SO 答案中显示情况的最快方法。两者都行。

【讨论】:

【参考方案5】:

文档声明线程中运行的方法必须创建和销毁自己的自动释放池。所以如果你的代码有

[NSThread detachNewThreadSelector:@selector(doThings) toTarget:self withObject:nil];

方法应该是

- (void)doThings 
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  //Do your things here
  [pool release];

【讨论】:

以上是关于使用 [NSThread detachNewThreadSelector:toTarget:withObject:] 时如何设置自动释放池的主要内容,如果未能解决你的问题,请参考以下文章

iOS 多线程之 NSThread的基本使用

使用 NSThread 时出错

多线程NSThread

iOS多线程篇:NSThread

16iOS多线程篇:NSThread

NSThread