I want to fire off a method and have it run in the background - I do not care what really happens to it after it is started.
So in my main viewDidLoadMethod I have all o
First, you should name the queue using reverse domain syntax, eg "com.foo.myapp.backgroundwork" - this ensures uniqueness and consistency.
Second, you are immediately trying to release the queue you just created (and is presumably doing some work). Don't do that. Release the queue after work is done instead. The following is actually documented in the Concurrency programming guide, under "managing queue memory"
dispatch_async(newImages, ^{
[self getNewImages];
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_release(newImages); //this executes on main thread
});
});
edit: After re-reading the concurrency guide myself (I take my own medicine), I learned that the runtime will actually clean up a dispatch_queue that reaches 0 reference count on a background thread, so that shouldn't block your UI. It's still a bad idea to release it immediately, and instead follow the practice I demonstrated, where your task queues up it's cleanup on the main thread. So, in hindsight I'm thinking that your -getNewImages
method might be responsible for blocking your UI. Can you show some code from that method so we can rule that out?
I went the long way around but finally got the concept in my head and here is what is working perfectly for me:
dispatch_queue_t newImages = dispatch_queue_create("com.mydomain.app.newimagesinbackground", NULL); // create my serial queue
dispatch_async(newImages, ^{
[self getNewImages]; // call my function - this get added first in my serial queue
});
dispatch_async(newImages, ^{
dispatch_async(dispatch_get_main_queue(), ^{
// add this to the main queue as the last item in my serial queue
// when I get to this point I know everything in my queue has been run
dispatch_release(newImages);
});
});
My main problem was using the ASIHTTPRequest startAsynchronous method: http://allseeing-i.com/ASIHTTPRequest/How-to-use#using_blocks
That in essence was creating my bottleneck, 2000 images to get, 2000 asynchronous calls trying to be made. If I am already in the background the startSynchronous method works just fine and only 1 call is trying to run at a time.
To my understanding, ASIHTTPRequest startSynchronous requires NSRunLoop, and GCD serial queue thread doesn't have NSRunLoop. Thus, it doesn't work.
And your code seems that GCD serial queue is not needed at all. I think GCD global queue works fine with your code. For example,
- (void)getNewImages
{
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
/* snip */
for (Manufacturer *m in self.manufacturers)
{
/* snip */
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{
/* snip */
dispatch_async(queue, ^{
[responseString writeToFile:fileName atomically:YES encoding:NSUTF8StringEncoding error:nil];
});
for (NSDictionary* dict in array) {
/* snip */
ASIHTTPRequest *imageRequest = [ASIHTTPRequest requestWithURL:url];
[imageRequest setCompletionBlock:^{
/* snip */
dispatch_async(queue, ^{
[responseData writeToFile:[savePath stringByReplacingOccurrencesOfString:@"%20" withString:@" "] atomically:YES];
});
}];
/* snip */
[imageRequest startAsynchronous];
}
/* snip */
}];
/* snip */
[request startAsynchronous];
}
}
getNewImages method should be executed on the main thread, it requires the NSRunLoop of the main thread.