Wayne
Wayne

Reputation: 508

"__block" variable results in nil value when go out of block

I wanna use __block variable to get value in block. But when out of block, the __block variable seems to be nil. Why this would happen?

    NSString *fileName = [Tools MD5Encode:url];
    __block NSString *filePath = nil;
    [fileList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSString *aFileName = obj;
        if ([aFileName isEqualToString:fileName]) {
            NSString *path = [VERSIONS_INFO_DATA_DIRECTORY stringByAppendingPathComponent:aFileName];
            filePath = path;
            NSLog(@"filePath1 %@", filePath);
            *stop = YES;
        }
    }];
    //NSLog(@"filePath2 %@", filePath);
    //filePath seems to be nil
    return filePath;

When I change the code to [path copy], it works. But I have no idea whether this is a good idea. Any decision?

    NSString *fileName = [Tools MD5Encode:url];
    __block NSString *filePath = nil;
    [fileList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSString *aFileName = obj;
        if ([aFileName isEqualToString:fileName]) {
            NSString *path = [VERSIONS_INFO_DATA_DIRECTORY stringByAppendingPathComponent:aFileName];
            filePath = [path copy];
            NSLog(@"filePath1 %@", filePath);
            *stop = YES;
        }
    }];
    //NSLog(@"filePath2 %@", filePath);
    return [filePath autorelease];

Upvotes: 5

Views: 1107

Answers (3)

Tim Reddy
Tim Reddy

Reputation: 4438

http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html

Specifically:

Without ARC, __block also has the side effect of not retaining its contents when it's captured by a block. Blocks will automatically retain and release any object pointers they capture, but __block pointers are special-cased and act as a weak pointer. It's become a common pattern to rely on this behavior by using __block to avoid retain cycles.

Under ARC, __block now retains its contents just like other captured object pointers. Code that uses __block to avoid retain cycles won't work anymore. Instead, use __weak as described above.

So you need to copy.

Upvotes: 5

David Gelhar
David Gelhar

Reputation: 27900

Is the use of blocks even an issue here?

Seems to me that this sequence of code:

NSString *filePath = nil;
NSString *path = [VERSIONS_INFO_DATA_DIRECTORY stringByAppendingPathComponent:aFileName];
filePath = path;
return [filePath autorelease];

is over-releasing filePath (because you don't own the result of -stringByAppendingPathComponent:, you should not be (auto-)releasing it)

Upvotes: 1

Greg Price
Greg Price

Reputation: 2556

It is ok here to use copy or retain on the path. The reason for your issue is that NSString objects are members of the convenience objects along with others like NSArray that you do not actually have to release and were already autoreleased by the system prior to the days of ARC. Personally, I didn't like that they did that cause it just caused confusion like this. Because the block finishes executing the system autoreleases the string object you allocated causing the leak.

Upvotes: 1

Related Questions