views:

39

answers:

4

Hi folks,

Here is my code that is being run in a background thread:

-(void)updateFAQCache {

    NSAutoreleasePool *objPool = [[NSAutoreleasePool alloc] init];

    // Grab the new plist
    NSMutableArray *arrLoadedData = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://myurl.com/"]];

    // If the data is not Nil, update the table view and cache with the new data
    if (arrLoadedData != Nil) {

        // Merge the new data into our IVar
        arrFAQData = arrLoadedData;

        // Update the table view
        [self performSelectorOnMainThread:@selector(refreshFAQTable) withObject:Nil waitUntilDone:NO];

        // Save the new data to the cache
        [arrFAQData writeToFile:self.strFAQCacheLocation atomically:YES];

    }

    [arrLoadedData release];

    [objPool release];

}

My issue is that it seems the contents of arrFAQData is being released when arrLoadedData is released. This DOES makes sense to me, but I need to figure out how to retain this data into my IVAR while allowing me to release the local variable, arrLoadedData?

Thanks for your help!

+3  A: 

In your code, arrFAQData is just an alias of arrLoadedData, so the underlying object will be released "at the same time" (it's the same object). You need to retain a reference to arrLoadedData, and store that.

arrFAQData = [arrLoadedData retain];
Adam Wright
+2  A: 

Define arrFAQData as a property with a retain keyword, then assign it like this:

self.arrFAQData = arrLoadedData;

This will retain arrLoadedData on assignment

Jacob Relkin
+1  A: 

In your .h file:

@private
NSArray *_arrFAQData;

@property (nonatomic, retain) NSArray *arrFAQData;

In your .m file:

@synthesize arrFAQData = _arrFAQData;

Then in your updateFAQCache method:

self.arrFAQData = arrLoadedData;
[arrLoadedData release];

Don't forget to add the following in the dealloc method:

[_arrFAQData release];
Stelian Iancu
Ups, didn't see you release the arrLoadedData. So discard that line from my answer.
Stelian Iancu
+1  A: 

In addition to the replies above, it's unsafe to set arrFAQData from a secondary thread like that. The main risk is that something in the main thread will be part way through doing something with the old value of arrFAQData when suddenly the value changes. Absolute worst case is something like being in the middle of this on the main thread:

for(id object in arrFAQData)
{
    ... something ...
}

If you release what arrFAQData is pointing to and put something else in on the secondary thread then you'll end up trying to access deallocated memory. You similarly can't keep arrFAQData as the same logical array and just copy the new objects into it since you may not modify an array while fast iterating.

Parallelism is too complicated a topic to really go into in depth, but as a quick fix, I recommend switching refreshFAQTable to a method that takes a new array as a parameter, and altering your code to:

[self performSelectorOnMainThread:@selector(refreshFAQTable:) withObject:arrLoadedData waitUntilDone:YES];

That'll obviously avoid any problems with the main thread operating on the array at the same time it is replaced.

Tommy
That's a great point. Do you have any good documentation on Parallelism that I can read up on?
Jesse Bunch