Jon*_*ugh 8 objective-c objective-c-blocks
以下代码崩溃,因为sentence当最后一个块退出时内容消失.
#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;
}
Run Code Online (Sandbox Code Playgroud)
使这项工作的正确/惯用方法是什么?
好吧,我离开并玩了一会儿 Xcode,这是正在发生的事情的模型,似乎与我所看到的相符。
\n\n我上面使用的块没有做任何特殊的事情,但enumerateObjectsUsingBlock代码似乎有自己的NSAutoreleasePool,所以这似乎是导致dealloc在对象上调用的原因alloc\'ed,但在块内自动释放。
以下代码的行为与我在上面看到的相匹配:
\n\n#import <Foundation/Foundation.h> \nint main (int argc, const char * argv[]) {\n NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];\n\n // simple block test - just iterate over some items and \n // add them to a string\n typedef void (^AccArrayBlock)(id obj, int idx, BOOL *stop);\n // items to \'process\'\n NSArray *items = [NSArray arrayWithObjects:@"why ", @"must ", @"this ",nil];\n int idx = 0;\n BOOL doStop = NO;\n // make sentence mutable, so we can assign it inside block\n __block NSString *sentence = @"";\n // make a similar block to what we\'d pass to enumerate...\n AccArrayBlock myBlock = ^(id obj, int idx, BOOL *stop)\n {\n // returns and assigns an autoreleased string object\n sentence = [sentence stringByAppendingFormat:@"(%d) %@ ",idx,obj];\n };\n // enumerate items and call block\n for (NSString *item in items) {\n // create a pool to clean up any autoreleased objects in loop\n // remove this line, and the sentence will be valid after loop\n NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];\n myBlock(item, idx++, &doStop);\n // drain the pool, autorelease objects from block\n [innerPool drain];\n if (doStop) {\n break;\n }\n }\n // faults if we drained the pool\n // Program received signal: \xe2\x80\x9cEXC_BAD_ACCESS\xe2\x80\x9d.\n NSLog(@"Sentence is %@",sentence);\n [pool drain];\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n如果我删除该innerPool对象,那么代码将按照我最初的预期工作,并且大概NSRunLoop池最终会清理各种NSString对象。
注意:此线程现在是“enumerateObjectsUsingBlock autorelease”的第二个 Google 结果:
\n\nGoogle \'enumerateObjectsUsingBlock+autorelease\'
\n\n第一个结果证实了这个答案。谢谢大家。
\n