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

时间:2012-07-11 16:08:27

标签: objective-c cocoa nsrunloop

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

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

由于如果没有源连接到运行循环,run方法会立即退出,这看起来像一个无限while循环,如果当前没有连接NSURLConnection,它将无用地消耗CPU资源运行循环。

另一方面,为了保持运行循环的活动,some suggests在运行循环中安排一个空端口:

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

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

那是什么方式?

(对于上下文,与其他许多人一样,我正在尝试将异步NSURLConnection封装在NSOperation内,这意味着它可以在主线程之外触发。此外,MVCNetworking示例代码,以及WWDC 2010会议 iPhone OS网络应用程序,似乎建议有一个专用于网络传输的独特辅助线程,以防止主线程上的延迟。)< / p>

1 个答案:

答案 0 :(得分:6)

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

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];
}