Domanda

Say I have a class:

@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

I understand that, in the dispatch_async block, self is being retained because of the _widget iVar. So let's say that some other non-main thread calls foo while the block on the main thread is being processed. All of a sudden, my block has it's _widget reference ripped out from underneath it and I get some EXC_BAD_ACCESS (SIGSEGV).

At first blush, I thought I would say:

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

But, this pattern becomes cumbersome if I have many iVars I need to make local.

I would like to know what I can do to avoid this situation without writing a bunch of boilerplate code?

È stato utile?

Soluzione

Accessing an instance variable from two separate threads at the same time is not safe. You need some kind of synchronization mechanism such as property or @synchronized block. For example:

@property(strong, readwrite) Widget* widget;

(Note the lack of nonatomic.)

And access the value via the property:

@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

Of course, if foo is called asynchronously, your self.widget could return nil. If this is not the behavior you want, your proposed local-variable solution is the way to go.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top