objective-c - 将对象分配给 block 外的变量

标签 objective-c objective-c-blocks

以下代码崩溃,因为 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/

相关文章:

objective-c - Objective-C 中的 Mach 端口消息

ios - 为什么阻止对象不能像NSObject一样释放内存?

ios - 访问属性时,点语法和 "->"有什么不同

iphone - Apple Mach-O 链接器错误 (2)

objective-c - 如果可能的话,如何在 Objective-C 中声明结构的 typedef 枚举

iphone - 如何在 iPhone 中以编程方式将图像旋转 90 度?

objective-c - @属性赋值

objective-c - 调用 block iOS

iphone - 如何为一组嵌套的 UIView animateWithDuration 调用调用单个完成 block ?

ios - block如何在非ARC环境中保留变量?