web-dev-qa-db-ja.com

AndroidのAsyncTaskに相当するiOS / Objective-C

AndroidでAsyncTaskを使用することに慣れています。サブクラスを作成し、サブクラスのインスタンスでexecuteを呼び出し、onPostExecuteをUIスレッドまたはメインスレッドで呼び出します。 iOSで同等のものは何ですか?

68
SundayMonday

元の質問への回答:

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オブジェクトとして扱われるため、これらの関数の呼び出しについて心配する必要はありませんのでご安心ください。 rob mayoff's great answer を参照すると、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.
_

4)複数のタスク/ブロック

GCDには、複数の非同期アクティビティが完了するまでタスクを続行できない場合に、複数の非同期ブロックの同期をサポートするグループ化インターフェイスが追加されます。 JörnEyrichとɲeuroburɳは、このトピックについてgeneしみなく説明しています here 。この機能が必要な場合は、数分かけて両方の回答をよく読んで、両者の違いを理解することを強くお勧めします。

documentation には、あなたがその傾向があるなら、トピックに関する豊富な情報があります。

101
eric.mitchell

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() updateメソッドとそれぞれを追加できます...現時点では、バックグラウンドサービスで非同期タスクを呼び出すため、使用しません。

お役に立てば幸いです。

18
IgniteCoders

以前のiOSバージョン(Grand Central DispatchのiOS 4よりも)をターゲットにしている場合、NSObject performSelectorメソッドを使用できます。

これは例です:

[self performSelectorInBackground:@selector(executeInBackground) withObject:nil];


-(void) executeInBackground
{
    NSLog(@"executeInBackground");

    [self performSelectorOnMainThread:@selector(executeOnMainThread) withObject:nil waitUntilDone:NO];
}

-(void) executeOnMainThread
{
    NSLog(@"executeOnMainThread");
}
5
JeanLuc

スイフト3

Androidバックグラウンドスレッドでタスクを実行し、終了したらUIを更新したいときは、AsyncTaskexample )を使用しました。 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
    }
}

ノート

1
Suragch