objective-c - Obj-C __block 变量保留行为

标签 objective-c memory-management objective-c-blocks

我在尝试从修改它的 block 外部访问 __block( block 可变)变量时遇到了一个奇怪的问题。这是一个非常简单的示例,我使用它只是为了更好地理解一般的 block ,但目前我有一个 Controller 使用这种方法创建一个字符串,其中包含 NSDictionary 的内容,它使用NSDictionaryenumerateKeysAndObjectsUsingBlock:

- (NSString*) contentsOfDictionary:(NSDictionary*)dictionary
{
    __block NSString *content = @"";

    [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){
        NSString* contentToAppend = [NSString stringWithFormat:@"Object:%@ for key:%@\n", obj, key];
        content = [content stringByAppendingString:contentToAppend];
        NSLog(@"Content in block:\n%@", content);
    }];

    NSLog(@"Content out of block:\n%@", content);

    return content;
}

当我使用包含以下内容的字典运行此方法时:

Value    Key
"Queen"  "card"
"Hearts" "suit"
"10"     "value"

content 变量在 block 中被正确修改,每次迭代我都会得到这个输出:

... block 中的内容:

Object:Queen for key:card

... block 中的内容:

Object:Queen for key:card
Object:Hearts for key:suit

... block 中的内容:

Object:Queen for key:card
Object:Hearts for key:suit
Object:10 for key:value

一旦代码跳出代码块,访问 content 字符串就会抛出一个 EXC_BAD_ACCESS 并且在一次运行中它似乎打印了一些垃圾内存(无法重现)...

是什么导致这个变量被提早释放?我的印象是给它一个 __block 定义意味着它在 block 内使用时被保留并在 block 退出时被释放 - 但是变量被保留并自动释放以开始凭借作为一个字符串文字,所以我希望它最早不会在该方法退出之前被释放。

最佳答案

这是你的问题:

content = [content stringByAppendingString:contentToAppend];

-stringByAppendingString: 返回一个新的、自动释放的对象。此对象的地址存储在 content 中。每次通过这个(隐式)循环——也就是说,每次调用所提供的 block ——都是在创建一个全新的对象,然后将该新对象的地址分配给 content。这些对象都不会超过其包含的自动释放池。

您应该做的是使用 NSMutableString 并直接将 contentToAppend 附加到可变字符串。例如:

- (NSString*) contentsOfDictionary:(NSDictionary*)dictionary
{
    NSMutableString *content = [NSMutableString string];
    [dictionary enumerateKeysAndObjectsUsingBlock:
    ^(id key, id obj, BOOL *stop){
        NSString* contentToAppend = [NSString stringWithFormat:
            @"Object:%@ for key:%@\n", obj, key];
        [content appendString:contentToAppend];

        NSLog(@"Content in block:\n%@", content);
    }];

    NSLog(@"Content out of block:\n%@", content);
    return content;
}

请注意,不再需要 __block,因为您没有在 block 内的任何位置分配给 content

关于objective-c - Obj-C __block 变量保留行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6362958/

相关文章:

ios - 静态单元格内的 UITableView

ios - 此类对于 key screenNumber 不符合键值编码

c++ - 如何在 C++ 中调试双重删除?

memory-management - Windows CE : Mapping Physical memory in user mode

Objective-c: block 和 NSEnumerationConcurrent 的问题

ios - 在 ViewWillAppear 上创建 UIAlertController 会发出警告

ios - 没有为 UITextField 正确添加 inputAccessoryView

iphone - 使用 Core Bluetooth 在后台获取蓝牙 LE 外设广告

c - 如何在不初始化变量的情况下读取整个内存堆栈?

objective-c - 我可以释放在 block 运行之前使用它的 block 外部创建的对象吗?