我熟悉AsyncTask
在Android中使用的方法:创建一个子类,execute
在该子类的实例上onPostExecute
调用,然后在UI线程或主线程上调用。iOS中的等效功能是什么?
Answers:
大型中央调度(GCD)提供了一种在后台执行任务的机制,尽管它在结构上与AsyncTask不同。要异步执行某些操作,您只需要创建一个队列(如线程),然后传递一个dispatch_async()
要在后台执行的块。我发现它比AsyncTask整洁,因为它不涉及任何子类。无论您要在后台执行的代码如何,它都可以即插即用。一个例子:
dispatch_queue_t queue = dispatch_queue_create("com.yourdomain.yourappname", NULL);
dispatch_async(queue, ^{
//code to be executed in the background
});
如果要在后台执行任务并在后台任务完成后更新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
});
});
创建队列时,还可以使用该dispatch_get_global_queue()
函数获取具有特定优先级的全局调度队列(例如DISPATCH_QUEUE_PRIORITY_HIGH
)。这些队列是可普遍访问的,并且在您要将多个任务分配给同一线程/队列时很有用。请注意,内存完全由iOS管理。
有时有关于内存管理和调度队列,因为他们有自己的一些困惑dispatch_retain
/dispatch_release
功能。但是,请放心,它们被ARC视为Objective-C对象,因此您不必担心调用这些函数。参考rob mayoff关于GCD和ARC的很好的答案,您可以看到文档描述了与Objective-C对象等效的GCD队列:
* 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.
我还要补充一点,如果任务在多个异步活动完成之前无法继续执行,那么GCD的分组接口支持同步多个异步块。乔恩Eyrich和ɲeuroburɳ提供这个话题的一个慷慨的解释在这里。如果您需要此功能,我强烈建议您花几分钟时间仔细阅读它们的两个答案并了解它们之间的区别。
如果您愿意的话,文档中包含有关该主题的大量信息。
queue
需要与被破坏dispatch_release
?
queue
必须明确发布。否则,否,ARC将处理它。
iOS中没有用于该类的类,但是您可以使用队列进行模拟。您可以致电:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Your code to execute in background...
});
对于异步任务,在您的异步代码内部,调用下一个队列在视图中执行某些操作...:
dispatch_async(dispatch_get_main_queue(), ^{
//Your code to execute on UIthread (main thread)
});
然后,使用这两个队列,您可以创建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()
更新方法和相应的方法...目前暂时不使用它,因为我在后台服务中调用了异步任务。
希望对您有所帮助。
如果您定位的是较早的iOS版本(Grand Central Dispatch的版本高于iOS 4),则可以使用NSObject performSelector方法
并在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");
}
在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
}
}
这是带有PusblishProgress的ac#Xamarin.iOS版本:
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);
}
并实现:
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
}
}