Perfoming UI updates in secondary queue - iphone

I am using the new CoreMotion framework to monitor some of the hardware devices. Here is the typical code to do that:
-(void)startAccelerometer{
self.motion.accelerometerUpdateInterval = 1/30.0f;
NSOperationQueue* accelerometerQueue = [[NSOperationQueue alloc] init];
CMAccelerometerHandler accelerometerHandler = ^(CMAccelerometerData *accelerometerData, NSError *error) {
NSLog(#"Accelerometer realtime values");
NSLog(#"x=%f", accelerometerData.acceleration.x);
NSLog(#"y=%f", accelerometerData.acceleration.y);
NSLog(#"z=%f", accelerometerData.acceleration.z);
NSLog(#" ");
};
[self.motion startAccelerometerUpdatesToQueue:accelerometerQueue withHandler:[[accelerometerHandler copy]autorelease]];
}
That works just fine. Now I want to print the values on a UILabel, but since the CoreMotion frameworks has you use blocks, this is not guaranteed to be in the main queue (and in fact isn't for my app). Is it is "wrong" to just run the label's setter on the main queue like this?
-(void)startAccelerometer{
self.motion.accelerometerUpdateInterval = 1/30.0f;
NSOperationQueue* accelerometerQueue = [[NSOperationQueue alloc] init];
CMAccelerometerHandler accelerometerHandler = ^(CMAccelerometerData *accelerometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
self.lblAccelerometer.text = [NSString stringWithFormat:#"Accelerometer:\nx = %f\ny = %f\nz = %f",
accelerometerData.acceleration.x,
accelerometerData.acceleration.y,
accelerometerData.acceleration.z];
});
};
[self.motion startAccelerometerUpdatesToQueue:accelerometerQueue withHandler:[[accelerometerHandler copy]autorelease]];
}
It works just fine and I don't really see any reason why this would be frowned upon. Any thoughts on that?

This is a common method that I use in many projects. UI updates must occur on the main thread.
//Dispatch on background thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//background processing goes here
//Dispatch on main thread
dispatch_async(dispatch_get_main_queue(), ^{
//update UI here
});
});
In your case, your UI updates are occurring on the main thread. So I wouldn't worry about changing anything.

You are missunderstanding the concept of blocks, to put it simple:
Blocks are small pieces of code that can be handled as variables and be executed at a certain time or thread.
All UI updates MUST be performed on the main thread so as long as you do this it will be fine.
Codes can be executed in different threads with different priorities in sync or async mode. On your code you are doing it perfectly fine, you not only dispatch it to the Main Queue which is where uiupdates should be executed, but you are also dispatching it async which is the safest way to update send to the main queue (from your code i cannot tell if you are running this specific piece of code from the main queue or a secondary queue but if u were to dispatch a sync block from the main queue to the main queue your program would stop working)
For iOS documentation:
Use the dispatch_get_main_queue function to get the serial dispatch
queue associated with your application’s main thread. This queue is
created automatically for Cocoa applications and for applications that
either call the dispatch_main function or configure a run loop (using
either the CFRunLoopRef type or an NSRunLoop object) on the main
thread.
Read this here http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1

Related

Asynchronous Process Giving Me Trouble

I want to return information from a turn based game from the game center servers, which is all fine, but I want the player alias which is acquired using the asynchronous method:
[GKPlayer loadPlayersForIdentifiers:singleOpponentArray withCompletionHandler:^(NSArray *players, NSError *error) {
GKPlayer *returnedPlayer = [players objectAtIndex:0];
NSString *aliasToAdd = [NSString stringWithString:returnedPlayer.alias];
NSString *idToAdd = [NSString stringWithString:returnedPlayer.playerID];
NSDictionary *dictionaryToAddToAliasArray = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:aliasToAdd, idToAdd, nil] forKeys:[NSArray arrayWithObjects:#"alias", #"id", nil]];
[self.aliasArray addObject:dictionaryToAddToAliasArray];
}];
But the UI uses this information and it does't arrive in time. How can I make that method execute synchronously on the main thread?
Thanks.
Any UI related code must execute on the main thread.
If your app must wait for the asynchronous call to return, then first disable the UI. For example, set userInteractionEnabled = NO on your UIView.
Then, when the asynchronous methods returns, re-enable the UIView.
In the meantime, display some sort of activity indicator, e.g. UIActivityIndicatorView.
Of course, only do the above in a case where you can't perform the task in the background. Never needlessly block the UI. I'm sure you know that already of course but it's worth restating for any people new to the platform that might be reading this.
To invoke on the main thread, use one of the variants of NSObject's performSelectorOnMainThread method. Or, alternatively, queue it on gcd using the main queue by calling the dispatch_get_main_queue function.
You can do this using GCD functions:
// Show an UILoadingView, etc
[GKPlayer loadPlayersForIdentifiers:singleOpponentArray
withCompletionHandler:^(NSArray *players, NSError *error) {
// Define a block that will do your thing
void (^doTheThing)(void) = ^(void){
// this block will be run in the main thread....
// Stop the UILoadingView and do your thing here
};
// Check the queue this block is called in
dispatch_queue_t main_q = dispatch_get_main_queue();
dispatch_queue_t cur_q = dispatch_get_current_queue();
if (main_q != cur_q) {
// If current block is not called in the main queue change to it and then do your thing
dispatch_async(main_q, doTheThing);
} else {
// If current block is called in the main queue, simply do your thing
doTheThing();
}
}];

store data in database in background using multi-threading for iPhone [duplicate]

I have an iPhone app that is using sqlite 3.6 (not with FMDB) to store and load data. I load the database when the app loads and uses the same database connection through the whole app.
In a background thread the app downloads some data from a webserver and writes to the database. At the same time the main thread also might need to write to the same database. This sometimes leads to EXC_BAD_ACCESS as both threads are trying to access the database.
What is the best and easiest way to be able to use the database from different threads?
This is an example that shows the problem:
sqlite3 *database;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"database.db"];
if (sqlite3_open([path UTF8String], &database) != SQLITE_OK) {
sqlite3_close(database);
return YES;
}
[NSThread detachNewThreadSelector:#selector(test) toTarget:self withObject:nil];
[self test];
return YES;
}
-(void)test {
for (int i = 0; i < 2000; i++) {
NSLog(#"%i",i);
sqlite3_exec([self getDb],"UPDATE mytable SET test=''", 0, 0, 0);
}
}
EDIT:
After willcodejavaforfood's answer below I've tried to change my code to use a separate database object (connection) for each separate thread and also added sqlite3_busy_timeout() so that sqlite will retry to write if the database is busy. Now I don't get EXC_BAD_ACCESS anymore but I've noticed that not all data get inserted. So this is not a stable solution either. It seems to be really hard to get sqlite working with threading..
My new solution with separate connections:
-(void)test {
sqlite3 *db = [self getNewDb];
for (int i = 0; i < 2000; i++) {
NSLog(#"%i",i);
sqlite3_exec(db,"UPDATE mytable SET test=''", 0, 0, 0);
}
}
- (sqlite3 *)getNewDb {
sqlite3 *newDb = nil;
if (sqlite3_open([[self getDbPath] UTF8String], &newDb) == SQLITE_OK) {
sqlite3_busy_timeout(newDb, 1000);
} else {
sqlite3_close(newDb);
}
return newDb;
}
I solved this problem by using one thread and an NSOperationQueue to insert the Data. I would give it some thought. I've never been able to get a stable System with mutliple threads, and most writes aren't that important that queuing really helps.
As per request, some more Infos:
I have a subclass of NSOperation that I instantiate with the model object I want to store.
These operations are than submitted to an extension of NSOperationsQueue that runs in a seperate thread. This custom Queue just adds a pointer to the database instance. When the operation is executed, it uses the [NSOperationsQueue currentQueue] property to access the queue and than the database. On purpose, i used non-concurrent operations (maxOperations was set to 1)
Hence, only one query (or update) is executed at a time consecutivly, completely in the background.
Obviously you need some kind of callback after you're finished.
It is possibly not the fast, but the most stable and cleanest solution i could find.
Docs:
http://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationObjects/OperationObjects.html
http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/
http://icodeblog.com/2010/03/04/iphone-coding-turbo-charging-your-apps-with-nsoperation/
As you've noticed only one thread can access an sqlite database at a time. Options to prevent simultaneous access:
Create a new database connection in each thread and rely on file locking (costly).
Turn on sqlite3_config(SQLITE_CONFIG_SERIALIZED).
Use NSLock's.
Use GCD (Grand Central Dispatch) queue's.
The first three options may cause busy waiting (one thread waiting on another to release the lock) which is wasteful.
I use option 4 because it simplifies the task of creating new queries to run in the background and has no busy waiting. It also makes sure all queries execute in the order they were added (which my code tends to assume).
dispatch_queue_t _queue = dispatch_queue_create("com.mycompany.myqueue", DISPATCH_QUEUE_SERIAL);
// Run a query in the background.
dispatch_async(_queue, ^{
...some query
// Perhaps call a completion block on the main thread when done?
dispatch_async(dispatch_get_main_queue(), ^{
//completion(results, error);
});
});
// Run a query and wait for the result.
// This will block until all previous queries have finished.
// Note that you shouldn't do this in production code but it may
// be useful to retrofit old (blocking) code.
__block NSArray *results;
dispatch_sync(_queue, ^{
results = ...
});
...use the results
dispatch_release(_queue);
In a perfect world sqlite would let you perform simultaneous reads but only one write at a time (eg. like using dispatch_barrier_async() for writes and dispatch_async() for reads).
This is all explained in the Core Data Programming Guide in the section for Concurrency.
The pattern recommended for concurrent
programming with Core Data is thread
confinement.
You should give each thread its own
entirely private managed object
context and keep their associated
object graphs separated on a
per-thread basis.
There are two possible ways to adopt
the pattern:
Create a separate managed object
context for each thread and share a
single persistent store coordinator.
This is the typically-recommended
approach.
Create a separate managed object
context and persistent store
coordinator for each thread. This
approach provides for greater
concurrency at the expense of greater
complexity (particularly if you need
to communicate changes between
different contexts) and increased
memory usage.
I've tried these two solutions and they worked perfectly. You can either use critical sections or NSOperationQueue and I prefer the first one, here is the code for both of them:
define some class "DatabaseController" and add this code to its implementation:
static NSString * DatabaseLock = nil;
+ (void)initialize {
[super initialize];
DatabaseLock = [[NSString alloc] initWithString:#"Database-Lock"];
}
+ (NSString *)databaseLock {
return DatabaseLock;
}
- (void)writeToDatabase1 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
- (void)writeToDatabase2 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
OR to use the NSOperationQueue you can use:
static NSOperationQueue * DatabaseQueue = nil;
+ (void)initialize {
[super initialize];
DatabaseQueue = [[NSOperationQueue alloc] init];
[DatabaseQueue setMaxConcurrentOperationCount:1];
}
+ (NSOperationQueue *)databaseQueue {
return DatabaseQueue;
}
- (void)writeToDatabase {
NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(FUNCTION_THAT_WRITES_TO_DATABASE) object:nil];
[operation setQueuePriority:NSOperationQueuePriorityHigh];
[[DatabaseController databaseQueue] addOperations:[NSArray arrayWithObject:operation] waitUntilFinished:YES];
[operation release];
}
these two solutions block the current thread until the writing to database is finished which you may consider in most of the cases.

Facebook request thread problem

Alright I am kind of new to threads so I have this question.
I am trying to get information of friends from Facebook, and I do not want to do that on the main thread. but for some reason when the request is not on the main thread the callback does never get called and I don't know why!
I have an Array with all the ID's from my friends and loop through this array and create an object of my custom class Friend (which gets all the information I need) with every ID.
I add this object to an array.
This friend object makes an request to Facebook and handles the response to get the data I want.
here is the code:
dispatch_async(dispatch_get_global_queue(0, 0), ^(void) {
[self getFBFriendsInfo];
});
-(void)getFBFriendsInfo{
if (friendsInfoArray) {
[friendsInfoArray removeAllObjects];
}
else{
friendsInfoArray =[[NSMutableArray alloc]init];
}
for (int i=0; i<[UDID count]; i++) {
NSString *udid = [UDID objectAtIndex:i];
FriendsInfo *friend =[[FriendsInfo alloc] initWithFacebook:facebook andUdid:udid];
[friendsInfoArray addObject:friend];
[friend release];
}
dispatch_async(dispatch_get_main_queue(), ^(void) {
[delegate friendsInfosAvailable:friendsInfoArray];
});
}
and in my custom class I do this:
[facebook requestWithGraphPath:udid andDelegate:self];
with this the callback's are never called! only if I do the request on the main thread it works:
dispatch_async(dispatch_get_main_queue(), ^(void) {
[facebook requestWithGraphPath:udid andDelegate:self];
});
This is why on a different thread you get no response:
Facebook will use NSURLConnection to perform requests. For the connection to work correctly the calling thread’s run loop must be operating in the default run loop mode (Read NSURLConnection class reference). When you use dispatch_async() there is no run loop operating in the default run loop mode (unless you are on the main dispatch queue, therefore running on the main thread). Hence, I figure the request isn't even sent (You can check that sniffing your network if you wish.).
So, in a nutshell, you should make your request on the main thread; as it is asynchronous, it wont freeze your app. Then, if the processing of the response is too expensive, handle it in the background.
I really hope this helps.
My best.

Using an application-lifetime-thread other than the main thread

I've a multi-threading application in which each thread has to do some job, but at a certain point some code needs to be executed serially (like writing into sqlite3 database), so I'm calling that code to be performed on main thread using:
[self performSelectorOnMainThread:#selector(serialJob:) withObject:object waitUntilDone:YES];
and every thing went just fine except that when that code needs some time the user interaction with the application gets disabled until that code has been finished, so is there any way to make another ONE thread that can be run on background and can be called whenever I need it just like the main one so I can replace the previous call with:
[self performSelector:#selector(serialJob:) onThread:REQUIRED_THREAD withObject:object waitUntilDone:YES];
this thread should be some class's static data member to be accessed from all over the code.
any help would be very appreciated, and many thanks in advance...
This is quite easy to do, just spawn your thread and let it run it's runloop using [[NSRunLoop currentRunLoop] run]. That's all that is required to be able to use performSelector:onThread: with a custom thread.
If you are on iOS 4 or newer you should consider using Grand Central Dispatch queues instead of threads though. The GCD APIs are much easier to use and can utilize the system resources much better.
Like Sven mentioned, look into Grand Central Dispatch.
You can create a queue like this:
dispatch_queue_t myQueue = dispatch_queue_create("com.yourcompany.myDataQueue", NULL);
Now you can call blocks on that queue:
dispatch_async(myQueue, ^{
// Your code to write to DB.
});
When you're done, don't forget to release the queue:
dispatch_release(myQueue);
Due to the my question that I need the current thread to be blocked until the database job has been finished, I've tried these two solutions and they worked perfectly. You can either use critical sections or NSOperationQueue and I prefer the first one, here is the code for both of them:
define some class "DatabaseController" and add this code to its implementation:
static NSString * DatabaseLock = nil;
+ (void)initialize {
[super initialize];
DatabaseLock = [[NSString alloc] initWithString:#"Database-Lock"];
}
+ (NSString *)databaseLock {
return DatabaseLock;
}
- (void)writeToDatabase1 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
- (void)writeToDatabase2 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
OR to use the NSOperationQueue you can use:
static NSOperationQueue * DatabaseQueue = nil;
+ (void)initialize {
[super initialize];
DatabaseQueue = [[NSOperationQueue alloc] init];
[DatabaseQueue setMaxConcurrentOperationCount:1];
}
+ (NSOperationQueue *)databaseQueue {
return DatabaseQueue;
}
- (void)writeToDatabase {
NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(FUNCTION_THAT_WRITES_TO_DATABASE) object:nil];
[operation setQueuePriority:NSOperationQueuePriorityHigh];
[[DatabaseController databaseQueue] addOperations:[NSArray arrayWithObject:operation] waitUntilFinished:YES];
[operation release];
}
these two solutions block the current thread until the writing to database is finished which you may consider in most of the cases.

Invoke model method with block that will run on the main thread

one of the central tenets of the architecture of my latest app is that I'm going to call methods on the app's model which will be async and accept failure and success scenario blocks.
i.e., The UI calls the model method with 2 blocks, one for success and one for failure.
This is great because the context of the original call is retained, however, the block itself is called on the background thread. Is there anyway of calling a block on the main thread??
Hopefully I have explianed it ok, if not, basically, my model methods are async, return immediately and create a new thread on which to run the op. Once the op returns I will invoke a block which will postprocess the returned data, THEN i need to call the block for the success scenario defined by the called inside the UI. However, the success and failure scenario blocks defined in the UI should be called in the main thread because I need to interact with UI elements which should only be done on the main thread I believe.
many thanks
Something like this is probably what you're after:
- (void) doSomethingWhichTakesAgesWithArg: (id) theArg
resultHandler: (void (^)(BOOL, id, NSError *)) handler
{
// run in the background, on the default priority queue
dispatch_async( dispatch_get_global_queue(0, 0), ^{
id someVar = [theArg computeSomething];
NSError * anError = nil;
[someVar transmuteSomehowUsing: self error: &anError];
// call the result handler block on the main queue (i.e. main thread)
dispatch_async( dispatch_get_main_queue(), ^{
// running synchronously on the main thread now -- call the handler
handler( (error == nil), theArg, anError );
});
});
}
If you are using GCD, you can use the "get main queue":
dispatch_queue_t dispatch_get_main_queue()
Call this inside an async dispatch. i.e.
dispatch_async(dispatch_get_main_queue(), ^{
/* Do somthing here with UIKit here */
})
The example block above could be running in an async background queue and the example code would send the UI work off to the main thread.
Similar approach works also with NSOperationQueue:
NSBlockOperation *aOperation = [NSBlockOperation blockOperationWithBlock:^
{
if ( status == FAILURE )
{
// Show alert -> make sure it runs on the main thread
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Alert" message:#"Your action failed!" delegate:nil
cancelButtonTitle:#"Ok" otherButtonTitles:nil] autorelease];
[alert show];
}];
}
}];
// myAsyncOperationQueue is created somewhere else
[myAsyncOperationQueue addOperation:aOperation];
NSObject has a method:
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
Create a method that takes a NSDictionary parameter in a convenient class that will always be around (like your app delegate, or a singleton object), package up the block and its parameters into a NSDictionary or NSArray, and call
[target performSelectorOnMainThread:#selector(doItSelector) withObject:blockAndParameters waitUntilDone:waitOrNot];