Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I safely access the contents of an NSArray property from a secondary thread?

I have an app (using retain/release, not GC) that maintains an NSArray instance variable, which is exposed as a property like so:

@interface MyObject : NSObject
{
    NSArray* myArray;
}
@property (copy) NSArray* myArray;
@end

I want to access the contents of this array from a secondary thread, which is detached using -performSelectorInBackground:withObject:. It is possible and indeed likely that the array will change during the execution of the secondary thread.

In the secondary thread I want to do something like this:

if([self.myArray containsObject:foo])
{
    //do stuff
}

From reading the threading documentation, it seems I should be able use the @synchronized directive in the accessors like so:

@implementation MyObject
- (NSArray *)myArray
{
    NSArray *result;
    @synchronized(self)
    {
        result = [myArray retain];
    }
    return [result autorelease];
}

- (void)setMyArray:(NSArray *)aMyArray
{
    @synchronized(self)
    {
        [myArray release];
        myArray = [aMyArray copy];
    }
}
@end

Is this all I need to do to ensure thread safety, or is it more complex?

Update: I've subsequently found a great article on Apple's site that addresses this issue in depth: http://developer.apple.com/mac/library/technotes/tn2002/tn2059.html

like image 952
Rob Keniger Avatar asked Dec 13 '25 12:12

Rob Keniger


1 Answers

Your code above protects you from setting the array concurrently, or getting the array while another is setting it. Since it is a non-mutable array, this protects the array itself just fine.

However, if by "the array will change" you mean you'll be editing the items inside the array, you could still have some problems. For example, if the array was filled with NSMutableStrings, and you had a thread that ran:

NSMutableString *foo = [myObject.myArray objectAtIndex:0];
[foo appendString:@"foo"];

and another that ran

NSMutableString *bar = [myObject.myArray objectAtIndex:0];
[bar appendString:@"bar"];

The access to the array would be safe (one thread would have to wait for the other to access it), however, access to the foo/bar pointer (which is the same) would not be, since both calls to 'appendString' are outside of the @synchronized block.

If this is how your array will change, you'll need to synchronize these points of access as well. Either with more @synchronized blocks, or other types of locks. See Using Locks

like image 156
bobDevil Avatar answered Dec 16 '25 09:12

bobDevil



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!