【问题标题】:Memory management and performSelectorInBackground:内存管理和 performSelectorInBackground:
【发布时间】:2011-10-29 18:01:54
【问题描述】:

哪个是对的?这个:

NSArray* foo = [[NSArray alloc] initWithObjects:@"a", @"b", nil];
[bar performSelectorInBackground:@selector(baz:) withObject:foo];

- (void)baz:(NSArray*)foo {
    ...
    [foo release];
}

或者:

NSArray* foo = [[[NSArray alloc] initWithObjects:@"a", @"b", nil] autorelease];
[bar performSelectorInBackground:@selector(baz:) withObject:foo];

- (void)baz:(NSArray*)foo {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    ...
    [pool release];
}

我知道第一个可行,但 Clang 抱怨它,所以我想知道是否有更好的模式可以使用。

我会“尝试”第二个,但使用自动发布,谁知道没有EXC_BAD_ACCESS 是否意味着你做对了,或者你很幸运......

【问题讨论】:

    标签: objective-c iphone cocoa-touch


    【解决方案1】:

    首先是错误的。

    performSelectorInBackground:withObject: 保留 bar 和 foo 直到任务执行。因此,您应该在创建 foo 时自动释放它,并让 performSelectorInBackground:withObject 负责其余的工作。见documentation

    后者是正确的,因为您在创建 foo 时会自动释放它。您在 baz 中创建的自动释放池与 foo 的内存管理的正确性无关。在 baz 中 inside 池分配和释放的自动释放对象需要该自动释放池,它根本不会触及 foo 的保留计数。

    【讨论】:

    • 我应该澄清一下:您必须在 -baz: 内创建并排出一个自动释放池,除非您知道其中不会发送任何东西 -autorelease 方法。最好的经验法则是假设这会发生并创建/排出一个自动释放池,如示例 2 所示。但使用 [pool drain],而不是 [pool release]。
    • 正如 Jim Dovey 所说:您通常需要像创建 main 函数一样创建自动释放池(请参阅线程编程指南)。重要的是要了解这个池与 foo 的自动释放无关。
    • @Jim,文档强调,如果您处于内存管理环境(我相信我们是 iPhone OS)中,则调用drain 等同于调用release。
    • 是的——但是 -drain 也会为任何环境做适当的事情,所以使用它,以防你的代码移动到桌面或收集的内存到达 iPhone。
    • @TeemuKurppa 能否请您引用 Apple 文档,其中指出 performSelectorInBackground 保留 self 及其 withObject 参数?暂时投反对票。
    【解决方案2】:

    现在正确的做法实际上是:

    NSArray* foo = [[[NSArray alloc] initWithObjects:@"a", @"b", nil] autorelease];
    [bar performSelectorInBackground:@selector(baz:) withObject:foo];
    
    - (void)baz:(NSArray*)foo {
        @autoreleasepool {
            ...
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-12
      • 2011-01-27
      • 2021-01-23
      • 2013-01-17
      • 2011-02-18
      • 2011-07-01
      • 2019-11-10
      相关资源
      最近更新 更多