I'm familiar with using AsyncTask
in Android: create a subclass, call execute
on an instance of the subclass and onPostExecute
is called on the UI thread or main thread. What's the equivalent in iOS?

- 19,147
- 29
- 100
- 154
6 Answers
Answer to Original Question:
Grand Central Dispatch (GCD) offers a mechanism to perform tasks in the background, though it works in a structurally different way than AsyncTask. To perform something asynchronously, you just need to create a queue (like a thread) and then pass a block to dispatch_async()
to be performed in the background. I find it neater than AsyncTask, as there is no subclassing involved; it is more or less plug-and-play wherever you have code you'd like to execute in the background. An example:
dispatch_queue_t queue = dispatch_queue_create("com.yourdomain.yourappname", NULL);
dispatch_async(queue, ^{
//code to be executed in the background
});
Other Points:
1) Callbacks
If you want to perform a task in the background and update the UI (or do something on another thread) when the background task is done, you can simply nest the dispatch calls:
dispatch_queue_t queue = dispatch_queue_create("com.yourdomain.yourappname", NULL);
dispatch_async(queue, ^{
//code to be executed in the background
dispatch_async(dispatch_get_main_queue(), ^{
//code to be executed on the main thread when background task is finished
});
});
2) Global Queues
When creating a queue, you can also use the dispatch_get_global_queue()
function to get a global dispatch queue with a certain priority (such as DISPATCH_QUEUE_PRIORITY_HIGH
). These queues are universally accessible and are useful when you want to assign multiple tasks to the same thread/queue. Note that memory is managed for you completely by iOS.
3) Memory
There is sometimes some confusion regarding memory management and dispatch queues because they have their own dispatch_retain
/dispatch_release
functions. However, rest assured that they are treated as Objective-C objects by ARC, so you don't need to worry about calling these functions. Referencing rob mayoff's great answer regarding GCD and ARC, you can see the documentation describe GCD queues' equivalence with Objective-C objects:
* By default, libSystem objects such as GCD and XPC objects are declared as
* Objective-C types when building with an Objective-C compiler. This allows
* them to participate in ARC, in RR management by the Blocks runtime and in
* leaks checking by the static analyzer, and enables them to be added to Cocoa
* collections.
*
* NOTE: this requires explicit cancellation of dispatch sources and xpc
* connections whose handler blocks capture the source/connection object,
* resp. ensuring that such captures do not form retain cycles (e.g. by
* declaring the source as __weak).
*
* To opt-out of this default behavior, add -DOS_OBJECT_USE_OBJC=0 to your
* compiler flags.
*
* This mode requires a platform with the modern Objective-C runtime, the
* Objective-C GC compiler option to be disabled, and at least a Mac OS X 10.8
* or iOS 6.0 deployment target.
4) Multiple Tasks/Blocks
I'll add that GCD has a grouping interface supports synchronizing multiple asynchronous blocks if a task cannot continue until multiple asynchronous activities have completed. Jörn Eyrich and ɲeuroburɳ provide a generous explanation of this topic here. If you need this functionality, I would highly recommend taking a few minutes to read both of their answers closely and understand the differences between them.
The documentation has a wealth of information on the topic if you are so inclined.

- 1
- 1

- 8,817
- 12
- 54
- 92
-
3Interesting. Is there a callback that executes on the main thread? – SundayMonday Jul 30 '12 at 19:26
-
Doesn't `queue` need to be destroyed with `dispatch_release`? – Nick Dec 25 '13 at 17:13
-
As of iOS 6.0 (and OS X 10.8), ARC will manage Grand Central Dispatch objects as they are treated as Objective-C object. So, if you deployment target is < iOS 6.0 or OS X 10.8, then yes, `queue` must be explicitly released. Otherwise, no, ARC will handle it. – eric.mitchell Feb 13 '14 at 20:01
There are no classes for that in iOS but you can simulate it using queues. You can call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Your code to execute in background...
});
for async tasks and inside your async code call next queue to do something in the view...:
dispatch_async(dispatch_get_main_queue(), ^{
//Your code to execute on UIthread (main thread)
});
Then, using this two queues you can create a asyncTask class, add this class to your project to implement them:
//
// AsyncTask.h
//
// Created by Mansour Boutarbouch Mhaimeur on 25/10/13.
//
#import <Foundation/Foundation.h>
@interface AsyncTask : NSObject
- (void) executeParameters: (NSArray *) params;
- (void) preExecute;
- (NSInteger) doInBackground: (NSArray *) parameters;
- (void) postExecute: (NSInteger) result;
@end
//
// AsyncTask.m
//
// Created by Mansour Boutarbouch Mhaimeur on 25/10/13.
//
#import "AsyncTask.h"
@implementation AsyncTask
- (void) executeParameters: (NSArray *) params{
[self preExecute];
__block NSInteger result;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
result = [self doInBackground:params];
dispatch_async(dispatch_get_main_queue(), ^{
[self postExecute:result];
});
});
}
- (void) preExecute{
//Method to override
//Run on main thread (UIThread)
}
- (NSInteger) doInBackground: (NSArray *) parameters{
//Method to override
//Run on async thread (Background)
return 0;
}
- (void) postExecute: (NSInteger) result{
//Method to override
//Run on main thread (UIThread)
}
@end
This is an example that I am using in a project:
#import "AsyncTask.h"
#import "Chat.h"
@interface SendChatTask : AsyncTask{
NSArray * chatsNotSent;
}
@end
#import "SendChatTask.h"
@implementation SendChatTask
- (void) preExecute{
//Method to override
}
- (NSInteger) doInBackground: (NSArray *) parameters{
//Method to override
NSString *sendChatsURL = [NSString stringWithFormat:@"%@%@%@",HOST, NAMESPACE,URL_SEND_CHAT];
chatsNotSent = [parameters objectAtIndex:0];
NSString *response;
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
//...
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[ChatJSONParser wrapChatArray: chatsNotSent] options:0 error:&error];
NSString *JSONString = [[NSString alloc] initWithBytes:[jsonData bytes] length:[jsonData length] encoding:NSUTF8StringEncoding];
[params setObject:JSONString forKey:@"chats"];
response = [HTTPClient executePOST:sendChatsURL parameters:params];
if([respuesta isEqualToString:@"true"]){
return 1;
}else{
return -1;
}
}
- (void) postExecute: (NSInteger) result{
//Method to override
if (result == 1) {
for (Chat *chat in chatsNotSent) {
chat.state = STATE_NOT_SENT;
[chat save];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate refreshChat];
}
} else {
}
}
@end
And the following call:
[[[SendChatTask alloc] init] executeParameters:[NSArray arrayWithObjects: chatsNotSent, nil]];
You can add a publishProgress()
update method and respective... I don't use it for the moment because I call my async task in background services.
I hope it's helpful.

- 4,834
- 3
- 44
- 62
-
probably more descriptive than necessary... the bad of copy/paste – IgniteCoders Oct 02 '14 at 10:52
if your targeting earlier iOS Version (than iOS 4 for Grand Central Dispatch) you could use the NSObject performSelector methods
Execute on Background Thread performSelectorInBackground:withObject:
And execute on MainThread performSelectorOnMainThread:withObject:waitUntilDone:
This is an example:
[self performSelectorInBackground:@selector(executeInBackground) withObject:nil];
-(void) executeInBackground
{
NSLog(@"executeInBackground");
[self performSelectorOnMainThread:@selector(executeOnMainThread) withObject:nil waitUntilDone:NO];
}
-(void) executeOnMainThread
{
NSLog(@"executeOnMainThread");
}

- 4,783
- 1
- 33
- 47
-
6
-
1i totally agree, that optimizing for low iOS Version is probably not always worth it. But i rather prefer the ObjectiveC-API of performSelector than the API in C of Grand Central Dispatch. the iOS 2+ part is just a bonus feature. – JeanLuc Jul 30 '12 at 20:00
-
1Yeah, I understand that. I actually like the C-style syntax better because you don't need to create a new method for each task, and sharing variables is easier (NSObject methods can only take one parameter, and passing an array of assorted objects is messy) – eric.mitchell Jul 30 '12 at 20:30
-
@JeanLuc What are the performance implications between this solution and the one from @Rickay? – SundayMonday Jul 30 '12 at 21:41
-
Honestly I can't say. It's possible that at runtime, they both do pretty much the same thing, but the syntax is just different. I don't really know. http://stackoverflow.com/questions/5653522/grand-central-dispatch-vs-nsthread might give you some information – eric.mitchell Jul 30 '12 at 21:46
-
@Rickay: i agree performOnMainThread/performOnBackgroundThread methods with Blocks would be nice. concerning sharing variables i would use either properties inside the object itself or create a class with values you want to pass. – JeanLuc Jul 30 '12 at 22:06
-
@SundayMonday i don't think, there is a performance difference. under the hood, they are doing the same thing: changing threads. if you can't decide which solution to use in your implement: flip a coin. – JeanLuc Jul 30 '12 at 22:07
Swift 3
In Android when I wanted to run a task on a background thread and then update the UI when it finished, I used AsyncTask
(example). Now when I am making iOS versions of my apps, I use Grand Central Dispatch (GCD) to do the same thing. Here is how it is done with Swift:
DispatchQueue.global(qos: .background).async {
// code to be run on a background task
DispatchQueue.main.async {
// code to be run on the main thread after the background task is finished
}
}
Notes

- 484,302
- 314
- 1,365
- 1,393
Here is a c# Xamarin.iOS version with PusblishProgress:
internal abstract class AsyncTask : NSObject
{
protected abstract nint DoInBackground(NSArray parameters);
protected abstract void PostExecute(nint result);
public void ExecuteParameters(NSArray @params)
{
this.PreExecute();
DispatchQueue.GetGlobalQueue(DispatchQueuePriority.Default).DispatchAsync(() =>
{
//We're on a Background thread
var result = this.DoInBackground(@params);
DispatchQueue.MainQueue.DispatchAsync(() => {
// We're on the main thread
this.PostExecute(result);
});
});
}
protected abstract void PreExecute();
protected void PublishProgress(NSArray parameters)
{
InvokeOnMainThread(() => {
// We're on the main thread
this.OnProgressUpdate(parameters);
});
}
protected abstract void OnProgressUpdate(NSArray parameters);
}
And implementation:
internal class MyAsyncTask : AsyncTask
{
protected override void OnProgressUpdate(NSArray parameters)
{
// This runs on the UI Thread
}
protected override nint DoInBackground(NSArray parameters)
{
// Do some background work
// ....
var progress = NSArray.FromObjects(1, "Done step 1");
PublishProgress(progress);
return 0;
}
protected override void PostExecute(nint result)
{
// This runs on the UI Thread
}
protected override void PreExecute()
{
// This runs on the UI Thread
}
}