12

我有一种将文件保存到互联网的方法,它可以工作但速度很慢。然后我想让用户界面更流畅,所以我创建了一个 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];

谢谢。

4

5 回答 5

15

首先,你们都在为保存代码创建一个新线程,然后异步使用 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];
}
于 2008-10-30T04:12:00.440 回答
6

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

- (void) save:(id)arg {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    //Existing code

    [pool drain];
}

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

于 2008-10-30T02:06:20.257 回答
2

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

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];
于 2008-10-30T03:54:40.863 回答
0

在线程中,您需要在执行任何其他操作之前创建一个新的自动释放池,否则网络操作将出现您所看到的问题。

于 2008-10-30T01:58:58.400 回答
0

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

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

于 2008-10-31T04:58:45.353 回答