【问题标题】:Retaining an object created in an NSThread保留在 NSThread 中创建的对象
【发布时间】:2009-08-04 02:37:10
【问题描述】:

我有以下由调用新线程(使用 NSThread)产生的方法:

- (void) updateFMLs {   
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSArray *temp = [[NSArray alloc] initWithArray:someArrayFromAnotherProcess];

    [self performSelectorOnMainThread:@selector(doneLoading:) withObject:temp waitUntilDone:NO];
    [pool release];
}

我的doneLoading: 方法如下所示:

- (void) doneLoading:(NSArray *)obj {
    myArray = [[NSArray alloc] initWithArray:obj copyItems:NO];
}

myArray 的内容无效。如何保留myArray 的内容,以便以后在我的应用中使用它们?

附: myArray在类头文件中定义。

【问题讨论】:

  • “失效”是什么意思。它们是否正在被释放?
  • 顺便说一句,您正在泄漏“temp”数组。你分配了一个数组(+1 保留计数),但你永远不会释放它。
  • 是的,它们似乎在我通过 doneLoading 的过程中被解除分配......即使在 doneLoading 中没有任何内容,除了上面显示的行,以任何方式改变 myArray
  • 用线程相关的标签重新标记,并删除了不太相关的 iPhone 标签。

标签: objective-c cocoa multithreading memory-management thread-safety


【解决方案1】:

如果您的后台线程做了一些工作并且需要“传递”NSArray 给您的主线程,那么 doneLoading 需要做的就是:

-(void)doneLoading:(NSArray *)obj
{
    [myArray release]; // release the previous array and its objects
    myArray = [obj retain];
    // now use myArray, refresh tables, etc.
}

(很可能)不需要制作另一个数组副本,这可能是根本问题。您还应该在调用performSelector 之后调用[temp release],因为已经保留了该参数。

如果myArray 的内容以某种方式变得有效,那么它们就会在某处被双重释放。 myArray 将保留添加到其中的所有对象。您提到 myArray 本身正在变得无效,因此请尝试使用此模式重写您的后台线程和 doneLoading 方法。

最后你应该使用[pool drain] 代替[pool release]

【讨论】:

  • 如果另一个线程在您的 release 消息和新数组的分配之间使用 myArray 会发生什么?
  • 大概(基于问题)他仅在主线程上使用myArray。看来他的后台线程设置了一个新模型,然后需要将其传递给主线程进行处理。他的问题更多是关于内存管理而不是线程同步。为了解决您提出的问题,他需要添加 @synchronized(self){} 块。另外,updateFMLs 在调用 doneLoading 后立即退出。
【解决方案2】:

您发布的代码看起来不错,除了updateFMLs 中的内存泄漏。您可能在其他地方过度释放对象。我猜想someArrayFromAnotherProcess 是在哪里制作的。

【讨论】:

  • 当我调试 updateFMLs - temp 填充了正确的数据。当它被传递给 doneLoading 然后变得无效时,这让我很困惑......
  • 它们可能在 updateFMLs 中释放池时被释放,这将在调用 doneLoading 之前发生。
  • 如果是这种情况,那么您必须找到错误发布的位置,然后删除该版本。它似乎不在您发布的代码中。
  • Tom Dalling:但是数组中的对象被数组保留,他正在泄漏(它不是自动释放的)。如果他修复了泄漏,那么这将成为一个问题,但这不是显示的代码中的问题。
  • 我认为它类似于 [[[MyItem new] autorelease] autorelease] 会释放对象,即使泄露的数组有保留对象。
【解决方案3】:

上述选项的替代方法是将 myArray 声明为标题中的原子属性

@property (atomic,retain) NSArray *myArray;

然后在 updateFMLs 中,您应该能够简单地从辅助线程调用 setter。显然,这只有在您愿意为原子属性支付性能损失时才有效。

- (void) updateFMLs {
    NSAutoreleasePool *pool - [[NSAutoreleasePool alloc] init];
    NSArray *temp = [[NSArray alloc] initWithArray:someArrayFromAnotherProcess];
    [self setMyArray:temp];
    [temp release];
    [pool drain];
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-06
    • 2014-05-06
    • 1970-01-01
    • 2013-11-06
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多