Lothar
Lothar

Reputation: 13065

Updating a NSTableView data source from a background thread

What is the best way to synchronize a data source which is updated frequently from a background thread with the GUI main thread?

Should i put a pthread mutex around each method call? This seems to be pretty heavy too me.

EDIT: I'm looking for a 10.5 solution

Upvotes: 1

Views: 1450

Answers (2)

Aidan Steele
Aidan Steele

Reputation: 11330

Is this on Snow Leopard or do you wish to retain compatibility with 10.2+? If you're dead-set on keeping backwards compatibility, you can factor out the code that applies the updates to another method and call it using performSelectorOnMainThread:withObject:waitUntilDone:

Alternatively, if you'd prefer to play with new toys and keep your code more readable (i.e. keep the number of methods to a minimum), you could do it in-line courtesy of blocks and Grand Central Dispatch. Something like the following might suffice:

// The following line is (presumably) executed in your background thread
NSMutableArray *newEntries = [self doSomeHeavyLiftingInBackground];
dispatch_async(dispatch_get_main_queue(), ^{
    /* The following lines are executed in the context of your main 
    thread's run loop. You don't need to mess about with locks as it
    will not be executed concurrently with UI updates. */
    id<NSTableViewDataSource> dataSource = [self getDataSource];
    NSMutableArray *dataSourceInnards = [dataSource whyIsThisMethodHere];
    [dataSourceInnards addObjectsFromArray:newEntries];
    [dataSource tellTableViewToReload];
});

This has the advantage of not having to contort your code to the pass-a-single-object-to-a-separate-method pattern.

Upvotes: 1

Jose Ibanez
Jose Ibanez

Reputation: 3345

You could always update the model and table view on the main thread. There are functions in NSObject like performSelectorOnMainThread:withObject:waitUntilDone: that allows you to easily perform a function call on the main thread. So you could update your model with:

[model performSelectorOnMainThread:@selector(addObject:) withObject:newObject waitUntilDone:YES];

and then, update your tableview with this:

[tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];

Things get more complicated if you need to pass more than one object, because then you need to use invocations, but I've found that these functions can be used most of the time.

Upvotes: 2

Related Questions