相当于Android的AsyncTask的iOS / Objective-C

我熟悉在Android中使用AsyncTask :创build一个子类,在子类的实例上调用execute ,并在UI线程或主线程上调用onPostExecuteiOS中有什么等价物?

回答原始问题:

Grand Central Dispatch(GCD)提供了一种在后台执行任务的机制,尽pipe它与AsyncTask在结构上有所不同。 要asynchronous执行某些操作,只需创build一个队列(如线程),然后将一个块传递给dispatch_async()以在后台执行。 我发现它比AsyncTask整洁,因为没有子类涉及; 无论你想在后台执行哪个代码,它都或多或less是即插即用的。 一个例子:

 dispatch_queue_t queue = dispatch_queue_create("com.yourdomain.yourappname", NULL); dispatch_async(queue, ^{ //code to be executed in the background }); 

其他要点:

1)callback

如果您想在后台执行任务并在后台任务完成时更新UI(或者在另一个线程上执行某些操作),则可以简单地嵌套调度调用:

 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)全局队列

创build队列时,还可以使用dispatch_get_global_queue()函数获取具有一定优先级的全局调度队列(如DISPATCH_QUEUE_PRIORITY_HIGH )。 这些队列是普遍可访问的,并且在您想要将多个任务分配给同一个线程/队列时非常有用。 请注意,内存是完全由iOSpipe理的。

3)记忆

内存pipe理和调度队列有时会有一些混淆,因为他们有自己的dispatch_retain / dispatch_release函数。 但是,请放心,它们被ARC视为Objective-C对象,因此您不必担心调用这些函数。 参照rob mayoff关于GCD和ARC 的很好的回答 ,你可以看到文档描述了GCD队列与Objective-C对象的等价关系:

 * 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 (eg 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)多任务/块

我将补充说,如果一个任务在多个asynchronous活动完成之前无法继续,那么GCD有一个分组接口支持同步多个asynchronous块。 JörnEyrich和ɲeuroburɳ 在这里提供了对这个主题的慷慨解释。 如果您需要此function,我强烈build议花几分钟时间仔细阅读他们的答案,并了解他们之间的差异。

如果您非常喜欢这个文档 ,那么这个文档就有很多这方面的信息。

在iOS中没有类,但是你可以使用队列来模拟它。 你可以打电话给:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //Your code to execute in background... }); 

asynchronous任务,并在你的asynchronous代码调用下一个队列在视图中做一些事情…:

 dispatch_async(dispatch_get_main_queue(), ^{ //Your code to execute on UIthread (main thread) }); 

然后,使用这两个队列,你可以创build一个asyncTask类,将这个类添加到你的项目来实现它们:


 // // 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 

这是我在一个项目中使用的一个例子:


 #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 

接下来的电话:

 [[[SendChatTask alloc] init] executeParameters:[NSArray arrayWithObjects: chatsNotSent, nil]]; 

您可以添加一个publishProgress()更新方法和相应的…我暂时不使用它,因为我在后台服务中调用我的asynchronous任务。

我希望这是有帮助的。

如果您定位iOS版本较早(iOS 4为Grand Central Dispatch),则可以使用NSObject performSelector方法

  • 在后台执行线程performSelectorInBackground:withObject:

  • 在MainThread上执行 performSelectorOnMainThread:withObject:waitUntilDone:

这是一个例子:

 [self performSelectorInBackground:@selector(executeInBackground) withObject:nil]; -(void) executeInBackground { NSLog(@"executeInBackground"); [self performSelectorOnMainThread:@selector(executeOnMainThread) withObject:nil waitUntilDone:NO]; } -(void) executeOnMainThread { NSLog(@"executeOnMainThread"); } 

Swift 3

在Android中,当我想要在后台线程上运行一个任务,然后在完成后更新UI时,我使用了AsyncTask ( 示例 )。 现在,当我制作应用程序的iOS版本时,我使用Grand Central Dispatch (GCD)来做同样的事情。 以下是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 } } 

笔记

  • Grand Central调度教程Swift