【问题标题】:NSThread with _NSAutoreleaseNoPool error带有 _NSAutoreleaseNoPool 错误的 NSThread
【发布时间】:2010-09-19 22:13:40
【问题描述】:

我有一种将文件保存到互联网的方法,它可以工作但速度很慢。然后我想让用户界面更流畅,所以我创建了一个 NSThread 来处理慢任务。

我看到如下错误列表:

_NSAutoreleaseNoPool(): Object 0x18a140 of class NSCFString autoreleased with no pool in place - just leaking

没有 NSThread,我这样调用方法:

[self save:self.savedImg];

并且我使用了以下使用NSThread来调用方法:

NSThread* thread1 = [[NSThread alloc] initWithTarget:self
                                        selector:@selector(save:)
                                              object:self.savedImg];
[thread1 start];

谢谢。

【问题讨论】:

    标签: cocoa multithreading memory-management memory-leaks


    【解决方案1】:

    在线程中,你需要在做任何事情之前创建一个新的自动释放池,否则网络操作会出现你看到的问题。

    【讨论】:

      【解决方案2】:

      您主要需要为线程创建一个自动释放池。尝试将您的保存方法更改为:

      - (void) save:(id)arg {
          NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
      
          //Existing code
      
          [pool drain];
      }
      

      你不会认为上面没有调用 NSAutoreleasePool 上的 release。这是一个特例。对于 NSAutoreleasePool 来说,在没有 GC 的情况下运行时,drain 相当于释放,并转换为对收集器的提示,它可能是运行收集的好点。

      【讨论】:

        【解决方案3】:

        您可能需要创建一个运行循环。我将添加到路易斯的解决方案:

        BOOL done = NO;
        
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        [NSRunLoop currentRunLoop];
        
        // Start the HTTP connection here. When it's completed,
        // you could stop the run loop and then the thread will end.
        
        do {
            SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, YES);
            if ((result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished)) {
                done = YES;
            }
        } while (!done);
        
        [pool release];
        

        【讨论】:

          【解决方案4】:

          首先,你们都在为保存代码创建一个新线程,然后异步使用 NSUrlConnection。 NSUrlConnection 在它自己的实现中也会衍生出另一个线程并在新创建的线程上调用你,这通常不是你想要做的事情。我假设您只是想确保您的 UI 在保存时不会阻塞...

          NSUrlConnection 也有同步版本,它会阻塞你的线程,如果你想启动自己的线程来做事,最好使用它。签名是

          + sendSynchronousRequest:returningResponse:error:
          

          然后,当您收到响应时,您可以回调您的 UI 线程。像下面这样的东西应该可以工作:

          - (void) beginSaving {
             // This is your UI thread. Call this API from your UI.
             // Below spins of another thread for the selector "save"
             [NSThread detachNewThreadSelector:@selector(save:) toTarget:self withObject:nil];    
          
          }
          
          - (void) save {
             NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
          
             // ... calculate your post request...
             // Initialize your NSUrlResponse and NSError
          
             NSUrlConnection *conn = [NSUrlConnection sendSyncronousRequest:postRequest:&response error:&error];
             // Above statement blocks until you get the response, but you are in another thread so you 
             // are not blocking UI.   
          
             // I am assuming you have a delegate with selector saveCommitted to be called back on the
             // UI thread.
             if ( [delegate_ respondsToSelector:@selector(saveCommitted)] ) {
              // Make sure you are calling back your UI on the UI thread as below:
              [delegate_ performSelectorOnMainThread:@selector(saveCommitted) withObject:nil waitUntilDone:NO];
             }
          
             [pool release];
          }
          

          【讨论】:

          • 同步调用的情况和签名关闭它应该是 NSURLConnection *conn = [NSURLConnection sendSyncronousRequest:postRequest returnedResponse:&response error:&error];
          【解决方案5】:

          我认为您没有任何理由为此使用线程。简单地在运行循环上异步执行它应该可以在不阻塞 UI 的情况下工作。

          相信运行循环。它总是比线程更容易,并且旨在提供相同的结果(从不阻塞的 UI)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-07-05
            • 1970-01-01
            • 1970-01-01
            • 2011-07-23
            • 1970-01-01
            • 2014-03-21
            相关资源
            最近更新 更多