2

我有一个正在重构的应用程序,我刚刚实现了多线程,以便 UI 可以运行得更流畅。在 iphone 模拟器中,我没有任何泄漏,但在运行 iOS 4.2 的 iPhone 3G 上进行测试时,我得到了内存泄漏。我已经做了很多寻找使用操作队列实现自动释放池的正确方法,我们将不胜感激。

我在我的视图控制器中创建了一个 nsoperationqueue

- (void)loadData
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSOperationQueue *queue = [NSOperationQueue new];  // creates multithread for loading data without slowing UI
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];

  [queue addOperation:operation];
  [operation release];
  [queue release];
  [pool release];
}
4

2 回答 2

2

首先,您不应该只是创建然后释放队列。将该队列创建为类的 ivars 之一,然后在您的视图控制器消失时释放它(您也可以取消任何挂起的操作并取消/等待任何正在运行的操作完成)更为自然。

其次,您不需要创建操作并将其添加到队列中的方法中的自动释放池,因为该方法是从主线程调用的。相反,您需要对象实际调用的方法中的自动释放池(这可能在另一个线程上运行)。

因此,您可能有以下内容(假设您将队列命名为 ivar queue_):

- (void)viewDidLoad
{
  [super viewDidLoad];

  if( !queue_ ) queue_ = [[NSOperationQueue alloc] init];
  // other view loading code
}

- (void)loadData
{
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];
  [queue_ addOperation:operation];
  [operation release];
}

- (void)firstRun
{
  // Here we may run on another thread, so 1) we need an autorelease pool; and
  // 2) we need to make sure we don't do anything that requires a runloop
  NSAutoreleasePool* threadPool = [NSAutoreleasePool new];

  // do long-running things

  [threadPool drain];
}

- (void)dealloc
{
  if( queue_ ) {
    [queue_ setSuspended:YES];
    [queue_ cancelAllOperations];
    // you need to decide if you need to handle running operations
    // reasonably, but don't wait here because that may block the
    // main thread
    [queue_ release];
  }
  // other dealloc stuff
  [super dealloc];
}

您还可以按需初始化队列,因此不要在 viewDidLoad 中进行初始化,而是检查它的存在并在必要时在您要添加操作的任何地方进行初始化。这可能包含在它自己的方法调用中,但是这里的延迟初始化可能并不是真正必要的,因为队列非常轻量级。

于 2010-12-29T20:49:06.233 回答
0

您应该NSAutoreleasePool在 NSOperation 将调用的方法的开头创建一个(在本例中为firstRun),并在方法结束时将其排空。

于 2010-12-29T20:41:49.163 回答