将对象分配给块外的变量 [英] Assigning objects to variable outside a block

查看:76
本文介绍了将对象分配给块外的变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于最后一个块退出时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;
}

完成这项工作的正确/惯用方式是什么?

解决方案

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

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

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

#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'的第二个Google结果:

What is the correct / idiomatic way to make this work?

Ok, I went away and played with Xcode for a bit, and here's a model of what's going on, that seems to match what I'm seeing.

The block I used above isn't doing anything special, but the enumerateObjectsUsingBlock code appears to have its own NSAutoreleasePool, so that seems to be what was causing dealloc to be called on objects alloc'ed, but autoreleased inside the block.

The following code matches in behavior what I'm seeing above:

#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;
}

If I remove the innerPool object, then the code works as I originally expected, and presumably the NSRunLoop pool will eventually clean up the various NSString objects.

NOTE: This thread is now the number 2 Google result for 'enumerateObjectsUsingBlock autorelease':

Google 'enumerateObjectsUsingBlock+autorelease'

The first result confirms this answer. Thanks all.

这篇关于将对象分配给块外的变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆