避免异步块中的意外解除分配

时间:2014-02-28 16:46:55

标签: objective-c objective-c-blocks dealloc

说我有课:

@interface MyClass : NSObject
@property(strong, nonatomic, readwrite) Widget* widget;
-(void)handleData:(NSData*)data;
-(void)foo;
@end

@implementation MyClass
-(void)handleData:(NSData*)data {
    //...do a bunch of handleData then...
    dispatch_async(dispatch_get_main_queue(), ^{
        [_widget someMethodWithData:data];
    });
}
-(void)foo {
    //...do a bunch of foo then...
    _widget = nil;
}
@end

据我所知,在dispatch_async区块中,由于self iVar,_widget被保留。因此,假设正在处理主线程上的块时,其他一些非主线程调用foo。突然之间,我的阻止了_widget引用从它下面撕掉了,我得到了一些EXC_BAD_ACCESS (SIGSEGV)

乍一看,我想我会说:

Widget* localWidget = _widget;
dispatch_async(dispatch_get_main_queue(), ^{
    [localWidget someMethodWithData:data];
});

但是,如果我需要制作本地的许多iVar,这种模式会变得很麻烦。

我想知道如果不编写一堆样板代码,我可以做些什么来避免这种情况?

1 个答案:

答案 0 :(得分:1)

同时从两个单独的线程访问实例变量是不安全的。您需要某种同步机制,例如属性或@synchronized块。例如:

@property(strong, readwrite) Widget* widget;

(注意缺乏非原子。)

通过属性访问该值:

@implementation MyClass
-(void)handleData:(NSData*)data {
    //...do a bunch of handleData then...
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.widget someMethodWithData:data];
    });
}
-(void)foo {
    //...do a bunch of foo then...
    self.widget = nil;
}
@end

当然,如果异步调用foo,你的self.widget可能会返回nil。如果这不是您想要的行为,那么建议的局部变量解决方案就是您的选择。