私はAsyncTask
Android での使用に慣れています: サブクラスを作成し、サブクラスexecute
のインスタンスを呼び出しonPostExecute
、UI スレッドまたはメイン スレッドで呼び出されます。iOSで同等のものは何ですか?
5 に答える
元の質問への回答:
Grand Central Dispatch (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
});
その他のポイント:
1) コールバック
バックグラウンドでタスクを実行し、バックグラウンド タスクが完了したときに 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) グローバル キュー
キューを作成するときに、このdispatch_get_global_queue()
関数を使用して、特定の優先度 ( などDISPATCH_QUEUE_PRIORITY_HIGH
) を持つグローバル ディスパッチ キューを取得することもできます。これらのキューはどこからでもアクセスでき、複数のタスクを同じスレッド/キューに割り当てたい場合に便利です。メモリは iOS によって完全に管理されることに注意してください。
3) メモリ
メモリ管理とディスパッチ キューには独自のdispatch_retain
/dispatch_release
関数があるため、混乱することがあります。ただし、これらは ARC によって Objective-C オブジェクトとして扱われるため、これらの関数の呼び出しについて心配する必要はありません。GCD と ARC に関するrob mayoff の素晴らしい回答を参照すると、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 (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) 複数のタスク/ブロック
複数の非同期アクティビティが完了するまでタスクを続行できない場合、GCD には複数の非同期ブロックの同期をサポートするグループ化インターフェイスがあることを付け加えておきます。Jörn Eyrich と ɲeuroburɳ は、このトピックについて寛大な説明を提供しています。この機能が必要な場合は、数分かけて両方の回答をよく読み、それらの違いを理解することを強くお勧めします.
ドキュメントには、このトピックに関する豊富な情報が含まれています。
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)
});
次に、この 2 つのキューを使用して 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 メソッドを使用できます。
バックグラウンドスレッドで実行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");
}
スイフト3
Android では、バックグラウンド スレッドでタスクを実行し、終了時に UI を更新したいときにAsyncTask
( example ) を使用しました。現在、アプリの 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
}
}