【问题标题】:Why is there no autorelease pool when I do performSelectorInBackground:?当我执行 performSelectorInBackground: 时,为什么没有自动释放池?
【发布时间】:2010-10-30 02:13:01
【问题描述】:

我正在调用一个进入后台线程的方法:

[self performSelectorInBackground:@selector(loadViewControllerWithIndex:) withObject:[NSNumber numberWithInt:viewControllerIndex]];

然后,我有这个被选择器调用的方法实现:

- (void) loadViewControllerWithIndex:(NSNumber *)indexNumberObj {
    NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init];
    NSInteger vcIndex = [indexNumberObj intValue];

    Class c;
    UIViewController *controller = [viewControllers objectAtIndex:vcIndex];

    switch (vcIndex) {
        case 0:
            c = [MyFirstViewController class];
            break;
        case 1:
            c = [MySecondViewController class];
            break;
        default:
            NSLog(@"unknown index for loading view controller: %d", vcIndex); // error
            break;
    }

    if ((NSNull *)controller == [NSNull null]) {
        controller = [[c alloc] initWithNib];
        [viewControllers replaceObjectAtIndex:vcIndex withObject:controller];
        [controller release];
    }

    if (controller.view.superview == nil) {
        UIView *placeholderView = [viewControllerPlaceholderViews objectAtIndex:vcIndex];
        [placeholderView addSubview:controller.view];
    }

    [arPool release];
}

虽然我确实为该线程创建了一个自动释放池,但我总是收到此错误:

2009-05-30 12:03:09.910 Demo[1827:3f03] *** _NSAutoreleaseNoPool(): Object 0x523e50 of class NSCFNumber autoreleased with no pool in place - just leaking
Stack: (0x95c83f0f 0x95b90442 0x28d3 0x2d42 0x95b96e0d 0x95b969b4 0x93a00155 0x93a00012)

如果我取消自动释放池,我会收到一大堆这样的消息。我还尝试围绕 performSelectorInBackground: 的调用创建一个自动释放池,但这无济于事。

我怀疑这个参数,但我不知道为什么编译器会抱怨一个 NSCFNumber。我错过了什么吗?

我的实例变量都是“非原子的”。会不会有问题?

更新:我可能还怀疑某些变量已添加到主线程的自动释放池(可能是 ivar)中,现在它试图在错误的自动释放池中释放该变量?如果是这样,我该如何解决? (该死,这个线程的东西很复杂;))

【问题讨论】:

  • 尝试在 _NSAutoreleaseNoPool 上设置断点,看看它是从哪里调用的
  • 切线问题:这里有一个新的控制器,在这个线程中本地分配,被添加到一个全局数组中,它的视图也被添加为一个子视图。这是因为对象是在与其容器不同的池中创建的吗?
  • @dk 你不应该问一个切题的问题,问一个单独的问题!无论如何,我强烈建议不要在非主线程中创建与 UI 相关的对象(控制器和视图)。这是一场等待发生的灾难。

标签: iphone multithreading cocoa-touch uikit autorelease


【解决方案1】:

这很可能是因为泄漏的对象(NSNumber)是从线程外部传入的参数。因此,这个变量属于调用线程(及其自动释放池)

线程调用周围的自动释放池不起作用的原因是线程创建者 (performSelectorInbackground) - 立即返回,很可能在线程仍在运行时返回。

我建议您在将选择器的参数作为参数传入后对其进行释放。

【讨论】:

  • 是的,将自动释放的对象传递给新线程会导致非常奇怪的行为。
【解决方案2】:

我同意这很可能是因为泄漏的对象(NSNumber)是从线程外部传入的参数。因此,这个变量属于调用线程(及其自动释放池)

调用线程应该使用NSAutoreleasePool 我建议您在参数中添加一条保留指令:

- (void) loadViewControllerWithIndex:(NSNumber *)indexNumberObj {
    NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init];
    [indexNumberObj retain];

    ....

    [arPool release];
  }

【讨论】:

    猜你喜欢
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多