2

リファクタリング中のアプリがあり、UI がよりスムーズに実行されるようにマルチスレッドを実装しました。iPhone シミュレーターではリークは発生しませんが、iOS 4.2 で実行されている iPhone 3G でテストすると、メモリ リークが発生します。operationqueue を使用して autoreleasepool を実装する正しい方法について多くの検索を行いました。助けていただければ幸いです。

ビューコントローラーに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

まず、キューを作成してから解放するだけではいけません。そのキューをクラスのivarの1つとして作成し、View Controllerがなくなったときにそれを解放する方が自然です(保留中の操作をキャンセルし、実行中の操作が完了するのをキャンセル/待機することもできます)。

次に、操作を作成してキューに追加するメソッドに自動解放プールは必要ありません。これは、そのメソッドがメインスレッドから呼び出されているためです。代わりに、オブジェクトが実際に呼び出すメソッドからの自動解放プールが必要です(これは別のスレッドで実行されている可能性があります)。

したがって、次のようになる可能性があります(キューに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

NSAutoreleasePoolNSOperation が呼び出すメソッドの開始時に を作成し(この場合はfirstRun)、メソッドの終了時にそれを排出する必要があります。

于 2010-12-29T20:41:49.163 に答える