iOS内联块很好,但声明为变量的块会导致内存问题

时间:2014-01-21 19:59:02

标签: ios objective-c-blocks exc-bad-access

我有一组看起来像这样的代码:

if(self.property == A) {
    [self.infoManager getThingA:^(NSString *thing, NSError *error) {
        self.textView.text = thing;
    }];
} else if(self.property == B) {
    [self.infoManager getThingB:^(NSString *thing, NSError *error) {
        self.textView.text = thing;
    }];
}

基本上,在这两种情况下,他们只是获取一个字符串来发布到TextView。字符串根据调用的方法而不同。

作为一般反对代码重复的人,我将其抽象为块变量:

void (^stringBlock)(NSString *thing, NSError *error) = ^void(NSString *thing, NSError *error) {
    self.textView.text = thing;
}

if(self.property == A) {
    [self.infoManager getThingA:stringBlock];
} else if(self.property == B) {
    [self.infoManager getThingB:stringBlock];
}

一切都很好。但是现在我的单元测试中出现了错误,因为看起来stringBlock过早被释放了。我想这是因为我在块运行后得到了EXC_BAD_ACCESS,调试器说stringBlock为NULL。

我没有在我的方法或单元测试中明确复制块。

1 个答案:

答案 0 :(得分:1)

上面声明的块称为独立块(其他类型称为内联块,类似于java中的内联匿名类)。当使用独立块时,我们需要遵守一些规则。

1.您不能在独立块对象中引用self。如果需要,必须将self对象作为参数传递给块。

2.您无法使用点表示法访问独立块内对象的属性。如果需要,请使用setter和getter方法。

...

所以在你的情况下,我们需要将self对象传递给块,如下所示。

void (^stringBlock)(NSString *thing, NSError *error, id self) = 
^void(NSString *thing, NSError *error, id self) {
     self.textView.text = thing;
}