将对象分配给块外的变量

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)

使这项工作的正确/惯用方法是什么?

Jon*_*ugh 4

好吧,我离开并玩了一会儿 Xcode,这是正在发生的事情的模型,似乎与我所看到的相符。

\n\n

我上面使用的块没有做任何特殊的事情,但enumerateObjectsUsingBlock代码似乎有自己的NSAutoreleasePool,所以这似乎是导致dealloc在对象上调用的原因alloc\'ed,但在块内自动释放。

\n\n

以下代码的行为与我在上面看到的相匹配:

\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}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我删除该innerPool对象,那么代码将按照我最初的预期工作,并且大概NSRunLoop池最终会清理各种NSString对象。

\n\n

注意:此线程现在是“enumerateObjectsUsingBlock autorelease”的第二个 Google 结果:

\n\n

Google \'enumerateObjectsUsingBlock+autorelease\'

\n\n

第一个结果证实了这个答案。谢谢大家。

\n