如何管理在辅助线程中运行的NSRunLoop的自动释放池?

Gui*_*ume 4 cocoa objective-c nsrunloop

在Apple的MVCNetworking示例代码中,NetworkManager该类包含此方法以在专用于网络活动的辅助线程中维护运行循环(以便NSURLConnection异步运行):

- (void)networkRunLoopThreadEntry
{
    while(YES) {
        NSAutoreleasePool *pool;
        pool = [[NSAutorelease alloc] init];
        [[NSRunLoop currentRunLoop] run];
        [pool drain];
    }
}
Run Code Online (Sandbox Code Playgroud)

因为run如果没有连接到运行循环源方法立即退出,这看起来像一个无限while这是会无谓地消耗CPU资源,如果目前没有连接到运行循环NSURLConnection的循环.

另一方面,为了保持运行循环活动,一些人 建议在运行循环中安排一个空端口:

 - (void)networkRunLoopThreadEntry
 {
     NSAutoreleasePool *pool = [[NSAutorelease alloc] init];
     NSPort *port = [NSPort port];
     [[NSRunLoop currentRunLoop] addPort:port forMode:NSRunLoopCommonModes];
     [NSRunLoop run];
     [pool drain];
 }
Run Code Online (Sandbox Code Playgroud)

但是,在这种情况下,我担心该run方法永远不会退出,这意味着池永远不会被耗尽,这意味着在辅助线程中分配和自动释放的所有对象都将泄漏.

那是什么方式?

(对于上下文,和其他许多人一样,我正在尝试将异步封装NSURLConnection在a中NSOperation,这意味着它可以在主线程之外触发.此外,MVCNetworking示例代码,以及WWDC 2010会话Network Apps for iPhone操作系统,似乎建议有一个专用于网络传输的独特辅助线程以防止主线程上的延迟.)

rob*_*off 6

您可以CFRunLoopObserverkCFRunLoopBeforeWaiting活动创建一个并将其添加到运行循环中.在观察者的标注中,释放旧池并创建一个新池.未经测试的例子:

static void resetPoolCallout(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    NSAutoreleasePool **poolPointer = (NSAutoreleasePool **)info;
    [*poolPointer release];
    *poolPointer = [[NSAutoreleasePool alloc] init];
}

- (void)networkRunLoopThreadEntry {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSPort *port = [NSPort port];
    [[NSRunLoop currentRunLoop] addPort:port forMode:NSRunLoopCommonModes];

    CFRunLoopObserverContext observerContext = {
        .version = 0,
        .info = (void*)&pool,
        .retain = NULL,
        .release = NULL,
        .copyDescription = NULL
    };
    CFRunLoopObserverRef observer = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting,
        true, 0, resetPoolCallout, &observerContext);
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);

    [[NSRunLoop currentRunLoop] run];

    CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
    CFRelease(observer);

    [pool release];
}
Run Code Online (Sandbox Code Playgroud)