Handle two Queue in Background - iphone

I am new in Iphone Development and i am working on Threading.
I have created two Queue like this:
dispatch_queue_t **Queue1** = dispatch_queue_create("Queue1", NULL);
dispatch_queue_t **Queue2** = dispatch_queue_create("Queue2", NULL);
I have added task in Queue1 like this:
dispatch_async(**Queue1**, ^{
[self HandleDownloadResponse];
});
dispatch_async(**Queue1**, ^{
dispatch_async(dispatch_get_main_queue(), ^{
});
});
When I will get a response of my web service, Queue1 is executed and it is using Sqllite3 database.
When My data transfer from my device, Queue2 is executed and it is also used sqllite3.
My Issue is: When I got a web service response first before My data transfer start, I got a database lock error.
So i want to pause(sleep) my Queue1 when my Queue2 becomes active.How can i do this?

you can try this
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// response from webservice
dispatch_async(dispatch_get_main_queue(), ^{
//insert into database
}
}

Related

How to put for loop to a separate thread

I have for loop that can read up to 100k rows.
When I start this function it block my UI until its done.
for (Item* sp in items){
data = [data stringByAppendingFormat:#"\"%#\",\"%#\","\n", ....];
}
How can I put this to separate thread so it doesn't block UI?
I don't think you've provided a complete example, but the simple use of Grand Central Dispatch should do the trick:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (Item* sp in items){
data = [data stringByAppendingFormat:#"\"%#\",\"%#\","\n", ....];
}
// Then if you want to "display" the data (i.e. send it to any UI-element):
dispatch_async(dispatch_get_main_queue(), ^{
self.someControl.data = data;
});
// else simply send the data to a web service:
self.webService.data = data;
[self.webService doYourThing];
});
This may suits you
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
for(Item* sp in items)
{
data = [data stringByAppendingFormat:#"\"%#\",\"%#\","\n", ....];
}
dispatch_async(dispatch_get_main_queue(), ^{
//UI updates using item data
});
});
Best way to use NSInvocationOperation.
NSOperationQueue *OperationQueue=[[NSOperationQueue alloc] init];
NSInvocationOperation *SubOperation=[[NSInvocationOperation alloc] initWithTarget:self selector:#selector(LoopOperation) object:nil];
[SubOperation setQueuePriority:NSOperationQueuePriorityVeryHigh]; //You can also set the priority of that thread.
[OperationQueue addOperation:SubOperation];
-(void)LoopOperation
{
for (Item* sp in items)
{
data = [data stringByAppendingFormat:#"\"%#\",\"%#\","\n", ....];
}
dispatch_async(dispatch_get_main_queue(), ^{
//UI updates using item data
});
}
If order doesn't matter in your loop I prefer to use dispatch_apply() inside of dispatch_async(). The difference is that a traditional for(...) loop will put all of the work on a single thread, while dispatch_apply() will perform the individual iterations in parallel on multiple threads, but as a whole the loop is synchronous, where the loop will not exit until all of the processing is complete.
A good test to see if order matters in your loop is whether the loop can be performed backwards with the same results.

Is there any difference between using dispatch_sync and writing code in-line(non-block without dispatch_sync)?

I'm making the app-book for ipad like app-magazine.
Now I'm using ScrollView and want to load many 1024*768 images(about 100 images), (As you know, If all images are loaded at once, It is impossible.)
so I load just 5 pages(current page & 2 pre pages & 2 next pages) and remove the other pages.
But, I have a question.
I made the method('loadTitlePage') for loading the page and I have to call this method when I want to load all pages.
So, I can't use dispatch_async but dispatch_sync.
Is there any difference between using dispatch_sync and writing code in line(non-block without dispatch_sync)?
It's my code.
[self loadTitlePage:currentPageNo];
dispatch_queue_t dqueue = dispatch_queue_create("scrollLoadTitlePage", NULL);
dispatch_sync(dqueue, ^{
[self loadTitlePage:currentPageNo-2]; });
dispatch_sync(dqueue, ^{
[self loadTitlePage:currentPageNo-1]; });
dispatch_sync(dqueue, ^{
[self loadTitlePage:currentPageNo+1]; });
dispatch_sync(dqueue, ^{
[self loadTitlePage:currentPageNo+2]; });
dispatch_sync(dqueue, ^{
[self removeTitlePage:currentPageNo-3 withNo:currentPageNo+3]; });
You can read here: using dispatch_sync in Grand Central Dispatch
In short.. dispatch_sync is equivalent to a mutex lock.. in your case I don't think there is any difference

Updating UI components from an async callback (dispatch_queue)

how can i update GUI elements with values from a queue?
if i use async queue construct, textlable don't get updated.
Here is a code example i use:
- (IBAction)dbSizeButton:(id)sender {
dispatch_queue_t getDbSize = dispatch_queue_create("getDbSize", NULL);
dispatch_async(getDbSize, ^(void)
{
[_dbsizeLable setText:[dbmanager getDbSize]];
});
dispatch_release(getDbSize);
}
Thank you.
As #MarkGranoff said, all UI needs to be handled on the main thread. You could do it with performSelectorOnMainThread, but with GCD it would be something like this:
- (IBAction)dbSizeButton:(id)sender {
dispatch_queue_t getDbSize = dispatch_queue_create("getDbSize", NULL);
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_async(getDbSize, ^(void)
{
dispatch_async(main, ^{
[_dbsizeLable setText:[dbmanager getDbSize]];
});
});
// release
}
Any UI update must be performed on the main thread. So your code would need to modified to use the main dispatch queue, not a queue of your own creation. Or, any of the performSelectorOnMainThread methods would work as well. (But GCD is the way to go, these days!)

Updating UI after completion of background thread

I'm implementing a simple twitter client for the iPhone using a UITableView. I fetch the picture of each twitter user in my feed when their cell appears in tableView: cellForRowAtIndexPath:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *profileImage = [tweet.user getProfileImageDataInContext:self.fetchedResultsController.managedObjectContext];
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = profileImage;
});
});
Here is the code to fetch the image:
if (!self.profileImage)
{
sleep(2);
self.profileImage = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.profileImageURL]];
//// if we recently scheduled an autosave, cancel it
[TwitterUser cancelPreviousPerformRequestsWithTarget:self selector:#selector(autosave:) object:context];
// request a new autosave in a few tenths of a second
[TwitterUser performSelector:#selector(autosave:) withObject:context afterDelay:0.2];
}
return [UIImage imageWithData:self.profileImage];
Here is the error I'm getting:
twitterClient[10743:15803] bool _WebTryThreadLock(bool), 0x59bac90: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
I think it's also worth mentioning that this happens when I scroll through the tableview very quickly when it hasn't been populated yet.
I would like the main UI to update upon completion of the download. The actual twitter app for iPhone does this quite well.
Any suggestions?
What’s the crash? A pretty standard pattern for things like this is
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// do background stuff
dispatch_async(dispatch_get_main_queue(), ^{
// do main-queue stuff, like updating the UI
});
});
You're using GCD fine, your crash is happening because you're calling dataWithContentsOfURL in a background thread, which is not thread safe.
See: Does -dataWithContentsOfURL: of NSData work in a background thread?

Updating the UI when using a serial queue

I am using a serial queue to do a background thread (block) for video processing. I want to update a UI component (specifically a progress bar). I've found that while I can interact with the UI, my progress bar is not updating with calls to setProgress (called from the block), until the thread has finished.
dispatch_queue_t dispatch_queue = dispatch_queue_create("somequeue", NULL);
[somebody doSomethingOnQueue:dispatch_queue usingBlock:^{
progressBar.progress = someFloat; //does not update
}];
You should update the UI on the main dispatch queue:
[somebody doSomethingOnQueue:dispatch_queue usingBlock:^{
…
dispatch_async(dispatch_get_main_queue(), ^{
progressBar.progress = someFloat;
});
}];
You can use performSelectorOnMainThread:withObject:waitUntilDone:.