以下代码崩溃,因为 sentence
的内容在最后一个 block 退出时消失。
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// simple block test - just iterate over some items and
// add them to a string
NSArray *items = [NSArray arrayWithObjects:@"why ", @"must ", @"this ",nil];
__block NSString *sentence = @"";
[items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
sentence = [sentence stringByAppendingFormat:@"%@",obj];
}];
// crash!
NSLog(@"Sentence is %@",sentence);
[pool drain];
return 0;
}
完成这项工作的正确/惯用方法是什么?
最佳答案
好吧,我去玩了一会儿 Xcode,这是一个正在发生的事情的模型,它似乎与我所看到的相符。
我在上面使用的 block 没有做任何特别的事情,但是 enumerateObjectsUsingBlock
代码似乎有它自己的 NSAutoreleasePool
,所以这似乎是导致 dealloc
在对象上调用 alloc'ed
,但在 block 内自动释放。
以下代码与我在上面看到的行为相匹配:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// simple block test - just iterate over some items and
// add them to a string
typedef void (^AccArrayBlock)(id obj, int idx, BOOL *stop);
// items to 'process'
NSArray *items = [NSArray arrayWithObjects:@"why ", @"must ", @"this ",nil];
int idx = 0;
BOOL doStop = NO;
// make sentence mutable, so we can assign it inside block
__block NSString *sentence = @"";
// make a similar block to what we'd pass to enumerate...
AccArrayBlock myBlock = ^(id obj, int idx, BOOL *stop)
{
// returns and assigns an autoreleased string object
sentence = [sentence stringByAppendingFormat:@"(%d) %@ ",idx,obj];
};
// enumerate items and call block
for (NSString *item in items) {
// create a pool to clean up any autoreleased objects in loop
// remove this line, and the sentence will be valid after loop
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
myBlock(item, idx++, &doStop);
// drain the pool, autorelease objects from block
[innerPool drain];
if (doStop) {
break;
}
}
// faults if we drained the pool
// Program received signal: “EXC_BAD_ACCESS”.
NSLog(@"Sentence is %@",sentence);
[pool drain];
return 0;
}
如果我删除 innerPool
对象,那么代码将按我最初的预期工作,并且大概 NSRunLoop
池最终会清理各种 NSString
对象。
注意:此线程现在是“enumerateObjectsUsingBlock autorelease”的第 2 个 Google 结果:
Google 'enumerateObjectsUsingBlock+autorelease'
第一个结果证实了这个答案。谢谢大家。
关于objective-c - 将对象分配给 block 外的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7169546/