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