我正在尝试从定义为类的一部分的obj-c块访问类ivars。我在这里不懂什么?

时间:2011-04-03 04:59:07

标签: objective-c objective-c-blocks

//class definition
@interface class1 : NSObject {
    NSMutableArray *array ;
    void (^test)() ;
}
@property( nonatomic,assign ) NSMutableArray *array  ;
@property( nonatomic,readonly ) void (^test)()  ;
@end

// implementation

@implementation class1

@synthesize array ;
@synthesize test ;

- (id)init
{
    self = [super init];
    a = [NSMutableArray arrayWithObjects:@"1",@"2", nil] ;
    test = ^ () {
        NSLog(@"length of array = %d",(int)[array count]);
    } ;
    return self;
}

// from main

    class1 *c = [[class1 alloc] init] ;

    c.test();

只要函数“c.test()”访问简单的ivars,即char,int等,c.test()就会执行并干净地返回。我试图访问一个obj-c对象,我得到例外。 我错过了什么?

2 个答案:

答案 0 :(得分:4)

BJ是正确的,您需要遵循内存管理规则,但在这种情况下, 的答案与块有关。

正如您的代码目前所代表的那样,array的正常属性将工作,直到当前的自动释放池耗尽。如果你分配/ init这些“class1”对象中的一个并立即尝试使用array属性,它将起作用(因为在对象的初始化和你尝试的时间之间不会消耗自动释放池访问数组)。

但是,一旦你把块放在那里,就不再是这种情况了。使用^{ ... }语法声明块时,此块将在调用堆栈的当前帧中分配。当您从init方法return时,会弹出当前帧。块ivar仍保留内存地址,但该地址不再存在块。删除堆栈框架时它被破坏了。

避免这种情况的方法是将块从堆栈复制到堆上,然后使用 块代替:

test = [^{  NSLog(@"block!"); } copy];

答案 1 :(得分:2)

你没有在init方法中保留数组,也没有调用setter方法。同样的块;如果您希望对象在当前方法的持续时间内保持不变,则需要通过调用setter方法或调用retain(或copy来获取它们的所有权。 )。

您的错误与块无关,而与内存管理有关。请注意,如果您正在使用垃圾收集,则仍需要调用copy以使块移动到堆