don*_*ain 8 memory-management objective-c objective-c-blocks
当我尝试__block从修改它的块外部访问(块可变)变量时,我遇到了一个奇怪的问题.这是一个非常好的玩具示例,我只是为了更好地理解块一般,但是目前我有一个控制器使用这个方法创建一个字符串,其内容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;
}
Run Code Online (Sandbox Code Playgroud)
当我使用包含内容的字典运行此方法时:
Value Key
"Queen" "card"
"Hearts" "suit"
"10" "value"
Run Code Online (Sandbox Code Playgroud)
所述content变量块内的正确修饰和我与每次迭代的输出:
......内容:
Object:Queen for key:card
Run Code Online (Sandbox Code Playgroud)
......内容:
Object:Queen for key:card
Object:Hearts for key:suit
Run Code Online (Sandbox Code Playgroud)
......内容:
Object:Queen for key:card
Object:Hearts for key:suit
Object:10 for key:value
Run Code Online (Sandbox Code Playgroud)
一旦代码走出块,但访问该content字符串会抛出一次EXC_BAD_ACCESS并且在一次运行时它似乎打印了一些垃圾内存(无法重现)......
是什么导致这个变量提前解除分配?我的印象是,给它一个__block定义意味着它在块中使用时保留并在块退出时释放 - 但变量被保留并自动释放以通过字符串文字开始,所以我期待它在此方法最早退出之后才能解除分配.
Jer*_*man 15
这是你的问题:
content = [content stringByAppendingString:contentToAppend];
Run Code Online (Sandbox Code Playgroud)
-stringByAppendingString:返回一个新的自动释放对象.该对象的地址存储在content.每个都经历这个(隐式)循环 - 也就是说,每次调用提供的块 - 正在创建一个全新的对象,然后分配该新对象的地址content.这些对象都不会超过其包含的自动释放池.
你应该做的是使用a NSMutableString并直接附加contentToAppend到mutable字符串.例如:
- (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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,__block不再需要,因为您没有分配到content块中的任何位置.
在内部,-enumerateKeysAndObjectsUsingBlock:使用自动释放池.__block在块的生命周期结束时不会保留范围对象,因此您最终会在块的范围内创建一个对象,然后在字典的自动释放池耗尽时释放该对象,这一切都在您尝试打印值之前发生content.
| 归档时间: |
|
| 查看次数: |
4085 次 |
| 最近记录: |