Утечка NSFileCoordinator

#iphone #objective-c #cocoa #nsfilecoordinator

#iPhone #objective-c #какао #nsfilecoordinator

Вопрос:

Это один тривиальный вопрос управления памятью, связанный с блоками, и я не уверен, когда / где fc следует выпустить

 NSFileCoordinator *fc = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
NSError *error = nil;
[fc coordinateWritingItemAtURL:sourceURL
                       options:NSFileCoordinatorWritingForDeleting
                         error:amp;error
                    byAccessor:^(NSURL *newURL) {

            // if error is not nil this block will not be called
            NSError *anError = nil;
            NSFileManager *fm = [NSFileManager defaultManager];
            [fm removeItemAtURL:newURL error:amp;anError];
            dispatch_async(q_main, ^{
                // change to the main queue and update the UI
                completion(anError);
        });
        // *** (1) Release here ? ***
        // [fc release];
        }];

// *** (2) or Release here ? ***
// [fc release]

if (error) {
    // change to the main queue and update the UI
    dispatch_async(q_main, ^{
        completion(error);
    });
}
  

Я думаю, что выпуск в (1) был бы в порядке (без утечек), но действительно ли это стандартный способ ведения дел? (освобождение объекта в блоке, который вызывает тот же объект ??). Я чувствую здесь некоторую странность.

В (2) тоже нормально, но только потому, что блок доступа вызывается синхронно.

В учебных целях… что, если этот блок доступа будет вызываться асинхронно? (Воображаемый случай, не необходимый для NSFileCoordinator) В таком случае мне нужно было бы создать fc ivar или это просто нормально для первого подхода?

Любая помощь приветствуется

🙂

Комментарии:

1. Это противоречивый ответ, но поскольку вы используете 10.7, почему бы не использовать ARC?

2. Я тоже так думал, но мне просто не нравится идея перехода на ARC без знания этих деталей 🙂

Ответ №1:

Для данного кода я бы выпустил в (2). Если вы отпустите at (1), вы можете снести fc из-под себя. Нет способа узнать, что fc может потребоваться сделать после вызова блока.

Для асинхронного случая я использовал подобный код (хотя и не с NSFileCoordinator ):

 __block NSWindowController *wc = [[NSWindowController alloc] initWithWindowNibName:@"foo"];
[NSApp beginSheet:[wc window] modalForWindow:[self window] completionHandler:^(NSInteger returnCode) {
    if(NSOKButton == returnCode) {
      // Do something
    }
    [wc release], wc = nil;
  }];
  

-beginSheet:modalForWindow:completionHandler: это категория, в которую я добавил NSApplication .

Комментарии:

1. Я думаю, что (2) — лучшее место 🙂 . Также вы сказали, что не выпустили бы его в (1), потому что мы не знаем, что fc происходит после блокировки, но в предполагаемом случае мы бы это сделали, и это было бы самое последнее, что он делает, было бы нормально выпустить его там?

2. Да, я думаю, если бы вы знали, что самое последнее, что делается fc , — это вызвать ваш блок, тогда освобождение в (1) или (2) было бы эквивалентно

3. Я думаю, что в ARC внутри блока генерируется неявное retain , поэтому все, что ему нужно, доступно, даже если вызывающий абонент давно ушел и выпустил все. Я полагаю, что без ARC, возможно, было бы неплохо сделать то же самое, и вы выпустили оба места, но добавили еще одно сохранение где-нибудь? Имеет ли это какой-либо смысл?