asynchronous asynctask使用 - iOS / Objective-C相當於Android的AsyncTask




onpostexecute in (5)

斯威夫特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
    }
}

筆記

我熟悉在Android中使用AsyncTask :創建子類,在子類的實例上調用execute ,在UI線程或主線程上調用onPostExecute什麼是iOS中的等價物?


回答原始問題:

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關於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 (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ɳ here提供了對此主題的慷慨解釋。 如果您需要此功能,我強烈建議您花幾分鐘時間仔細閱讀他們的答案,並了解它們之間的差異。

如果您願意, documentation有關於該主題的大量信息。


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方法

這是一個例子:

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


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

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

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

在您的活動中保留WeekReference會更加健壯:

public class WeakReferenceAsyncTaskTestActivity extends Activity {
    private static final int MAX_COUNT = 100;

    private ProgressBar progressBar;

    private AsyncTaskCounter mWorker;

    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task_test);

        mWorker = (AsyncTaskCounter) getLastNonConfigurationInstance();
        if (mWorker != null) {
            mWorker.mActivity = new WeakReference<WeakReferenceAsyncTaskTestActivity>(this);
        }

        progressBar = (ProgressBar) findViewById(R.id.progressBar1);
        progressBar.setMax(MAX_COUNT);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_async_task_test, menu);
        return true;
    }

    public void onStartButtonClick(View v) {
        startWork();
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        return mWorker;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mWorker != null) {
            mWorker.mActivity = null;
        }
    }

    void startWork() {
        mWorker = new AsyncTaskCounter(this);
        mWorker.execute();
    }

    static class AsyncTaskCounter extends AsyncTask<Void, Integer, Void> {
        WeakReference<WeakReferenceAsyncTaskTestActivity> mActivity;

        AsyncTaskCounter(WeakReferenceAsyncTaskTestActivity activity) {
            mActivity = new WeakReference<WeakReferenceAsyncTaskTestActivity>(activity);
        }

        private static final int SLEEP_TIME = 200;

        @Override
        protected Void doInBackground(Void... params) {
            for (int i = 0; i < MAX_COUNT; i++) {
                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.d(getClass().getSimpleName(), "Progress value is " + i);
                Log.d(getClass().getSimpleName(), "getActivity is " + mActivity);
                Log.d(getClass().getSimpleName(), "this is " + this);

                publishProgress(i);
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            if (mActivity != null) {
                mActivity.get().progressBar.setProgress(values[0]);
            }
        }
    }

}




android ios asynchronous android-asynctask