iphoneobjective-ccocoansfilecoordinator

NSFileCoordinator leak


This is one trivial question of memory management related with blocks and I am not sure when/where fc should be released

NSFileCoordinator *fc = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
NSError *error = nil;
[fc coordinateWritingItemAtURL:sourceURL
                       options:NSFileCoordinatorWritingForDeleting
                         error:&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:&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);
    });
}

I think releasing at (1) would be OK (no leaks) but is this really the standard way of doing things? (releasing an object in the block that the same object calls??). I feel some weirdness here.

At (2), Is also OK but only because the accessor block is called synchronously.

For learning purposes... what if that the accessor block would be called asynchronously? (An imaginary case not necessary of NSFileCoordinator) In such a case would I need to make fc an ivar or is it just fine to do as the first approach?

Any help is appreciated

:)


Solution

  • For the given code, I would release at (2). If you release at (1) you could tear down fc from underneath itself. There is no way to know what fc might need do after invoking the block.

    For the asynchronous case, I've used code like this (although not with 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: is a category I've added to NSApplication.