seanoshea
seanoshea

Reputation: 6106

UITableViewDataSource and Multithreading

I'm running into index beyond bounds exception in one of my UITableViews and I think it could be down to some multithreading issues. Here's what I believe is happening:

  1. I have a UITableView and it's data source is a regular NSMutableArray.
  2. This NSMutableArray which is backing my UITableView is updated every couple of seconds with the contents of an API response.
  3. After each update, UITableView's reloadData is being invoked to ensure that the user sees new data from the API server.
  4. Sometimes a index beyonds bounds exception gets thrown.

Here's my code:

-(NSMutableArray*) currentBetEvents
{
    return  currentMarketId == nil ? [[BFOpenBetsModel sharedInstance] betEvents] :     filteredBetEvents;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{    
    NSArray *betEvents = [self currentBetEvents];
    return [betEvents count];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSArray *betEvents = [self currentBetEvents];
    id obj = [betEvents objectAtIndex:indexPath.section] // this is where it blows up

Basically, I get an exception while trying to access an object in the betEvents structure at index 0.

What I believe is happening is:

  1. reloadData is called on the UITableView
  2. numberOfSectionsInTableView: is invoked which returns a value > 0.
  3. a rouge thread arrives and clears out the UITableView's data source.
  4. cellForRowAtIndexPath: is invoked and it bombs.

Is there any way to ensure that this doesn't happen? Do I need to start using some primitive locks on the data source to ensure that it doesn't get updated while the table is being updated?


EDIT Took another look at how the data structures returned by currentBetEvents can be altered and it looks like the filteredBets & betEvents can be cleared out as a result of the following code:

[[NSNotificationCenter defaultCenter] postNotificationName:kUserLoggedOutNotification object:nil];

This notification is posted whenever the user logs out. Whenever a user logs out of the app, I need to clear out the filteredBets and betEvents arrays. Is it possible that the following could happen:

  1. reloadData is called on the UITableView
  2. numberOfSectionsInTableView: is invoked which returns a value > 0.
  3. User logs out which kicks off the notification & clears out the data structures.
  4. cellForRowAtIndexPath: is invoked and it bombs.

Thanks,

Sean

Upvotes: 1

Views: 442

Answers (1)

Noah Witherspoon
Noah Witherspoon

Reputation: 57139

Definitely sounds like a threading problem. You might try something like this:

// view controller
@synchronized([[BFOpenBetsModel sharedInstance] betEvents])
{
    [self.tableView reloadData];
}

…

// data model
@synchronized(_betEvents) // or whatever the instance variable -betEvents returns is
{
    [_betEvents addObject:whatever];
}

Upvotes: 2

Related Questions