IOS開発のマルチスレッドNSThiread GCD NSOperation Runloop


IOSのプロセスとスレッド
长にとって一つのアプリはプロセスです。
ios開発では少ない運用プロセス間の通信(XPC)は、スレッドを使用することが圧倒的に多い。
ios開発では、流暢性とスレッドの安全を保証するために、UIに関するすべての操作をメインスレッドに置くべきであり、主スレッドもUIスレッドと呼ぶ場合がある。
UI体験に影響を与え、時間がかかる操作はできるだけメインスレッドに入れてください。ネットワーク要求やローカルのIOとの操作など。
IOS開発において、マルチスレッドに関する知識点は主にNSThread、GCD、NSOperation、Runloopを含む。
NSThread
NSthreadとはスレッドであり、その下の層はpthreadのパッケージであり、新しいスレッドを作成するために使用されています。NSThreadの一部の属性によって情報を取得することもできます。例えば、currentThread、isMainThreadなどです。

@property (readonly) BOOL isMainThread API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (class, readonly, strong) NSThread *currentThread;
例えば、私たちは、ネットワークから画像を要求し、UIページに表示する。

NSThread *downLoadImageThread = [[NSThread alloc] initWithBlock:^{
    //                    
    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:item.picUrl]]];
    self.rightimageView.image = image;  //UI           ,     
}];
//      
downLoadImageThread.name = @"downLoadImageThread";
[downLoadImageThread start]; //     
上のコードの中で、UI表示の操作をサブスレッドに置いています。これは規則に合わないです。iosではUI操作のコードをメインスレッドに入れなければなりません。そうでないと、システムがアラームを呼びます。
警報は図の通りです

GCD
GCDはコード中のdispatchの先頭に関するコードです。GCDはNSThreadの使用の不便を解決しました。スレッドに対する操作はキューに対する操作になります。これはスレッドの管理を簡単にしました。GCDは下の階にあります。私たちのためにスレッドの自動管理スレッドを実現しました。キューに対して操作すればいいです。スレッドと同様に、メイン列と非ホーム列があり、メインスレッドが格納されています。非ホーム列にはメインスレッドが格納されています。
次の図のように

GCDには主に3つの列があります。
第一:メインスレッドに対応するメイン列です。

dispatch_queue_main_t mainQueue = dispatch_get_main_queue(); //     
第二:非プライマリスレッドは優先度によって4の異なる優先度の非ホーム列に分類される。High/default/Low/Background
その定義された関数は以下の通りです。1番目のパラメータは優先度の選択で、2番目のパラメータは一時的に0を埋めることができます。

dispatch_queue_global_t downoadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //      
第三:カスタムキュー
作成関数は以下の通りです。最初のパラメータは列の名前を設定し、2番目のパラメータは列をシリアルに設定しますか?それとも同時にしますか?シリアルキューと并列列列の概念については、以下で详しく分析します。
シリアル:DISPATCH_QUUE_SERIAL
パラレル:DISPATCH_QUUE_CONCURRENT

dispatch_queue_t dispatch_queue_create(const char *_Nullable label,
		dispatch_queue_attr_t _Nullable attr);
GCDの使用は、同期実行と非同期実行に分けられる。
同期実行、つまりコード行の実行です。その関数の呼び出しは以下の通りです。

dispatch_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);
最初のパラメータのキュー名、2番目のパラメータはコードブロック、コードブロックはスレッドで実行するコードです。
非同期実行とは、コードが現在のコードブロックから飛び出すことができ、現在のコードを実行した後のコードです。その関数は以下の通りです。

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
最初のパラメータはキュー名で、2番目のパラメータは実行するコードブロックです。
もう一つの実行形態は、遅延実行であり、その関数は以下のように呼び出される。

void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
		dispatch_block_t block);
最初のパラメータは遅延時間で、後のパラメータは同じです。
概念解読:
同期実行:現在のスレッドでのみタスクを実行できます。新しいスレッドを開く能力はありません。
非同期実行:指定されたキューに非同期的にタスクを追加します。待ち時間はなく、タスクを実行し続けることができます。新しいスレッドでタスクを実行することができ、新しいスレッドを開く(作成する)能力を備えています。
シリアルキュー:タスクが一つしか実行されないたびに、タスクを次から次へと実行させます。スレッドを一つだけ開いて、一つのタスクを実行した後、次のタスクを実行します。
並列キュー:複数のタスクを同時に実行させることができます。複数のスレッドを開いてタスクを同時に実行することができます。
注意:並列キューの合併機能は非同期方法でのみ有効です。
ここでは、一例を挙げて、シリアルキューと同時キューの違いと同期実行と非同期実行の違いを説明します。
今5人が一つの門限をくぐると、この門限は全部で10個の入り口があります。管理人は同じ時間にいくつかの入り口を開けることができます。同じ時間に一人で通すかそれとも複数の人が一緒に通るかを決められます。しかし、デフォルトでは、管理人は入り口を一つだけ開けて、通路は一回に一人しか通れません。
この物語では、人は任務のようなもので、管理人はシステム、入り口はスレッドを表しています。
5人は5つのタスクがあり、10個の入り口は10本のスレッドを表しています。
シリアルの列は5人で長蛇の列を作っています。
併発列は、例えば5人で複数の列を作って、例えば2列、または3列です。
同期タスクは、管理者が一つのエントリ(現在のスレッド)だけを開いているようなものです。
非同期タスクは、管理者が同時に複数のエントリ(現在のスレッド+新規スレッド)を開いているようなものです。
今は管理人が複数の入り口(例えば3つの入り口)を開け、5人が複数のチーム(例えば3チーム)に並んでいます。この5人は同時に3人で門限をくぐります。
現在は管理人が入り口を1つ開けただけで、5人は複数の列に並んでいます。この5人は多くの列に並んでいますが、入り口を一つしか開けていません。この5人は早く行きたいですが、1つの入り口は一回に1人しか通れないので、みんなは次々に歩いていくしかないです。
GCDの言葉に言い換えると、
『非同期実行+合併キュー』とは、システムが複数のスレッド(メインスレッド+他のサブスレッド)を開いており、タスクが複数同時に実行されます。
「同期実行+合併キュー」とは、システムがデフォルトでメインスレッドを開いただけで、サブスレッドが開かれていません。タスクは同時キューの中にありますが、次々に実行するしかありません。
以下はGCDを使って、上のUI操作がサブスレッドで実行される警告問題を最適化します。

//   :  GCD  
    dispatch_queue_global_t downoadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //      
    dispatch_queue_main_t mainQueue = dispatch_get_main_queue(); //     
    //      ,    ,            
    //  :      ,       (   )          
    dispatch_async(downoadQueue, ^{  //   ,    
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:item.picUrl]]];
        dispatch_async(mainQueue, ^{  //  ,      UI  
            //       UI  ,    
            self.rightimageView.image = image;  //UI           ,     
        });
    });
NSOperation
GCDは対象向けのパッケージではないので、実行するコードは全部blockに書いてあります。普通のblockの実行をキャンセルするか、複数のblockの間で同期と相互反発を実現するか、操作は複雑です。
より上位のパッケージについては、システムが我々にNSOperationを提供し、それはシステムのGCDに対する一つの対象に向けたパッケージである。
NSOperationについては、後で詳しく調べてから共有しましょう。

Runloop
スレッドに合わせて、どのように业务ロジックの操作を行い、业务ロジックの実行を行いますか?各スレッドに対して、システムは内部実装を提供しています。この内部実装はRunloopです。Runloopは下の階のthreadに協力して、私達のジェスチャー、インタラクション、及びいくつかのポートの管理などを処理します。

一例を挙げると、メインスレッドはなぜ廃棄されないまま存在していますか?下の階はRunloopが維持されています。それはメインスレッドが実行されていない時に睡眠をとるようにしています。
最後に,巨視的からIOSのマルチスレッドに対する認識を示した。

以上がIOS開発のマルチスレッドNSThiread GCD NSOperation Runloopの詳細です。IOS開発のマルチスレッドに関する資料は他の関連記事に注目してください。