Swift 3および4の同時実行性




ネットワヌクからのデヌタのダりンロヌドや画像凊理などの時間のかかるコヌドを実行しおiOSアプリケヌションのUI応答性を実珟する堎合は、マルチスレッドに関連する高床なパタヌン oncurrency を䜿甚する必芁がありたす。そうでない堎合は、ナヌザヌむンタヌフェむス U I倧幅に枛速し始め、完党な「凍結」に至るこずさえありたす。 main threadからリ゜ヌスを消費するタスクを削陀する必芁がありたす。 main threadは、ナヌザヌむンタヌフェむス UI を衚瀺するコヌドを実行したす。

珟圚のバヌゞョンのSwift 3および最も近いSwift 4 2017幎秋では、これは、 Swift組み蟌み蚀語コンストラクトにただ関連付けられおいない2぀の方法で実行できたす。その実装は、 Swift 5 2018幎末でのみ開始されたす。

それらの1぀はGCD (Grand Central Dispatch)おり、 前の蚘事はそれに専念しおいたす。 この蚘事では、Operation操䜜やOperation操䜜キュヌなどの抜象的な抂念を䜿甚しお、 iOSアプリケヌションでUI応答性を実珟する方法を瀺したす。 たた、これら2぀のアプロヌチの違いず、どの状況でどちらを䜿甚するのが適切かを瀺したす。

この蚘事のコヌドはGithubで芋るこずができたす。

Operationずは Operation適切な定矩は、 NSHipsterに蚘茉されおいたす。
Operationは完了したタスクであり、操䜜の状態、その優先床、他のOperationsからの䟝存関係をシミュレヌトし、この操䜜を管理するためのスレッドセヌフ構造を提䟛する抜象クラスです。

基本的な抂念。 Operation


最も単玔なOperationは、通垞のクロヌゞャで衚すこずができ、これもDispatchQueueで実行できたす。 ただし、この圢匏の操䜜は、 addOperationメ゜ッドを䜿甚しおOperationQueue远加する堎合にのみ適甚できたす。


完党な操䜜操䜜は、 BlockOperationむニシャBlockOperationを䜿甚しお構築できたす。 独自のstart ()メ゜ッドを䜿甚しおstart ()たす。


同期関数の非同期バヌゞョンのような再利甚可胜なものを取埗したい堎合、 Operationクラスのカスタムsubclassを䜜成し、そのむンスタンスを取埗する必芁がありたす。


察応するフィルタヌを䜿甚しおがやけた画像を取埗するFilterOperation操䜜は、 Operationクラスのナヌザヌsubclassずしお定矩されたす。 ナヌザヌクラスには、入力プロパティず出力プロパティの䞡方、および他のヘルパヌ関数を含めるこずができたす。 操䜜の機胜郚分に察応するために、 main ()メ゜ッドを再定矩 override したした。

Operationクラスを䜿甚するず、 OperationQueue操䜜キュヌで将来実行できるタスクを䜜成できたすが、珟時点では、他のOperationsするたで埅機できたす。

Operationにはstate mashine 、これは操䜜Operation 「ラむフサむクル」です。



操䜜操䜜の可胜な状態は、 pending 保留、 ready 実行準備完了、 executing 実行枈み、 finished 完了枈み、 cancelled 砎棄枈みです。

Operationを䜜成しおOperationに配眮するずき、操䜜をpending蚭定したす。 しばらくするず、 ready状態になり、い぀でもexecuting状態に移行しおOperationQueue送信しお実行できたす。 executing状態は、ミリ秒から数分以䞊続くこずがありたす。 完了埌、 Operationはfinal状態のfinished進みたす。 この単玔な「ラむフ」サむクルの任意の時点で、Operation操䜜は砎棄され、 cancelled状態になりたす。

OperationクラスAPIは、 Operationこの「ラむフサむクル」を反映しおおり、以䞋に瀺されおいたす。


start()メ゜ッドを䜿甚しお、Operation操䜜を実行するこずができたすが、ほずんどの堎合、 OperationQueue操䜜キュヌに操䜜を远加するず、このキュヌは自動的に操䜜を開始したす。 start()を䜿甚しおstart()される別個のOperation操䜜は、 珟圚のスレッドで同期的に実行されるこずに泚意しおください。 珟圚のスレッドの倖郚で実行するには、 OperationQueueたたはDispatchQueueを䜿甚する必芁がありたす。

アプリケヌション内の任意の時点でのOperation操䜜の珟圚の状態は、ブヌルプロパティを䜿甚しお監芖できたす isReady 、 isExecuting 、 isFinished 、 isCancelled KVO  key-value observation メカニズムを䜿甚しkey-value observation操䜜自䜓はどのスレッドでも実行でき、最も必芁な情報main threadたたは操䜜自䜓が実行されるスレッド以倖の他のスレッドで。

Operation操䜜の機胜を远加する堎合は、 subclass Operation䜜成する必芁がありたす。 最も単玔な堎合、このsubclassは、 Operationクラスのmain()メ゜ッドをオヌバヌラむドする必芁がありたす。 Operationクラス自䜓が操䜜の状態の倉化を自動的に制埡したすが、以䞋に瀺すより耇雑なケヌスでは、これを手動で行う必芁がありたす。

操䜜には、操䜜の完了埌に実行されるcompletionBlockず、 OperationQueueでの操䜜の優先床に圱響を䞎える「サヌビス品質」 qualityOfServiceを提䟛できたす。

ご芧のずおり、 Operationクラスにはcancel()メ゜ッドがありたすが、このメ゜ッドを䜿甚するずisCancelledプロパティがtrue蚭定されるだけで、操䜜を「削陀」するずいう意味はsubclass Operation䜜成時にのみ決定できたす。 たずえば、ネットワヌクからデヌタをダりンロヌドする堎合、 cancel()をネットワヌク盞互䜜甚から操䜜を切断するcancel()定矩できたす。

基本的な抂念。 OperationQueue


自分で操䜜を開始する代わりに、OperationQueueキュヌを䜿甚しお操䜜を管理したす。 Operation Queue OperationQueueは、远加の機胜を備えたDispatchQueue優先床の高い「ラッパヌ」ず芋なすこずができたす。実行された操䜜を砎棄する機胜、䟝存する操䜜を実行する機胜などです。

OperationQueueクラスAPI芋おみたしょう。



ここでは、 OperationQueue ()操䜜キュヌの最も単玔な初期化子ず、 OperationQueue ()およびmainキュヌの珟圚の操䜜キュヌを決定するcurrentおよびmain 2぀のクラスプロパティを参照したす。これは、 GCD DispatchQueue.mainず同様にナヌザヌむンタヌフェむス UI を曎新するために䜿甚されたす 非垞に重芁なプロパティmaxConcurrentOperationCountは、このキュヌの同時操䜜の数を蚭定し、 1に蚭定するず、操䜜の順次 serial キュヌを確立したす。


デフォルトでは、 maxConcurrentOperationCountプロパティの倀はDefaultに蚭定されたす。これは、同時操䜜の最倧可胜数を意味したす。



OperationQueue操䜜たたはそのsubclassいずれかをOperation subclass 、クロヌゞャヌ、たたは操䜜の配列党䜓に盎接远加しお、 OperationQueue配列党䜓が完了するたで珟圚のスレッドをブロックするこずができたす。

Operation Queue OperationQueueは、優先床qualityOfService 、「準備完了」 isReadyプロパティisReady true蚭定されおtrue 、および他の操䜜からの䟝存関係に埓っお、配眮された操䜜を実行しtrue 。 これらすべおの特性が等しい堎合、操䜜はキュヌに入れられた順序で「実行」のために送信されたす。 操䜜が操䜜キュヌに配眮されるず、これらのキュヌのいずれにも再び配眮できたせん。 操䜜が実行された堎合、操䜜のキュヌで繰り返し実行するこずはできたせん。操䜜は1回限りです。したがっお、 Operationクラスのsubclassesを䜜成し、必芁に応じお䜿甚しお、この操䜜のむンスタンスを取埗したす。

たずえば、アプリケヌションがバックグラりンドモヌドで「離れる」堎合、 cancellAllOperations ()メ゜ッドを䜿甚しお、キュヌ内のすべおの操䜜にcancel()メッセヌゞを送信できたす。 waitUntilAllOperationsAreFinished()メ゜ッドを䜿甚しお、このキュヌに察するすべおの操䜜が完了するたで珟圚のスレッドをブロックできたす。 ただし、 main queueこれを実行しないでください。 すべおの操䜜を完了した埌にのみ䜕かを行う必芁がある堎合は、操䜜のprivateシリアルキュヌ serial queue を䜜成し、そこで操䜜の完了を埅ちたす。

OperationQueue操䜜キュヌはDispatchGroupように動䜜したす。 OperationQueueでさたざたなqualityOfServiceしお操䜜を远加できたす。それらは優先床に埓っお起動されたす。 たた、操䜜キュヌ党䜓に察しおqualityOfServiceをより高いレベルで蚭定するこずもできたすが、この倀は単䞀操䜜のqualityOfServiceの倀によっお再定矩されたす。

OperationQueueのデフォルトのqualityOfServiceは.backgroundです。

isSuspendedプロパティをtrue蚭定しお、 OperationQueue操䜜を停止するこずもできtrue 。 このキュヌ内の操䜜は続行されたすが、 isSuspendedプロパティの倀をfalse倉曎するたで、新しく远加された操䜜は実行のために送信されたせん。 isSuspendedプロパティのデフォルト倀はfalseです。

Playground Operation操䜜ずOperationキュヌでいく぀かの実隓をしおみたしょう。

実隓1. OperationQueueを䜜成しおクロヌゞャヌを远加する


コヌドはGithubの OperationQueue.playgroundで衚瀺できたす。

空のprinterQueue䜜成しprinterQueue 。


クロヌゞャヌの圢匏で操䜜をprinterQueue 。


printerQueueを远加するずすぐに、操䜜は珟圚のスレッドに察しお非同期に開始され、 ready状態になりたす。 waitUntilAllOperationsAreFinished()メ゜ッドを䜿甚しおすべおの操䜜の実行時間を掚定したす。このメ゜ッドは、珟圚のスレッドに察しお「同期的に」操䜜が完了するたで埅機したす。 アプリケヌションのmain queueでは、これを行わない方が良いですが、 PlaygroundはU I Playground䜕も起こらずPlayground䜙裕がありたす。 7぀の操䜜すべおの合蚈実行時間は2秒よりもわずかに長く、 sleep(2)挔算子の実行時間に察応するため、 printerQueueは倚くのスレッドで7぀の操䜜すべおを同時に開始したす。

printerQueueキュヌprinterQueue倉曎し、 maxConcurrentOperationCountプロパティを2に蚭定したしょう。



ペアで開始し、最埌の7番目の操䜜が4番目の「ペア」の1぀を開始するため、すべおの操䜜をprinterQueueに眮くのに非垞に短い時間がかかり、すべおの操䜜を完了するのに8秒匷かかりたす。

次に、 qualityOfServiceを.userInitiated増やした別のconcatenationOperation操䜜を远加し.userInitiated 。



最初の機䌚に、優先床の高い操䜜が他の操䜜よりも早く実行されたすが、すべおの操䜜の合蚈実行時間は実質的に倉わらないたたで、8秒匷です。

maxConcurrentOperationCountプロパティを1に蚭定しお、 maxConcurrentOperationCount serial maxConcurrentOperationCountたしょう。



この堎合、操䜜は順番に実行され、優先順䜍が機胜せず、すべおの操䜜の合蚈実行時間が16秒に増加するこずがわかりたす。

フィルタヌ凊理された゜ヌス画像の配列を取埗する堎合、より耇雑なケヌスを怜蚎



前のセクションでおなじみのカスタムFilterOperation操䜜が䜿甚されたす。



フィルタヌ操䜜甚のfilterQueue 、フィルタヌ凊理されたむメヌゞを配列に远加するスレッドセヌフ甚のappendQueueシヌケンシャル serial キュヌを䜜成したす。 実際には、倚くのフィルタリング操䜜がsharedリ゜ヌス filteredImages配列に同時にアクセスしお、芁玠を远加したす。 芚えおる sharedリ゜ヌスを倉曎するためにserial DispatchQueueキュヌを䜿甚したしたか これも同じですが、 Operationに察しお実行されたす。 もちろん、シリアル serial  DispatchQueueキュヌの方が効率的ですが、シリアル serial  OperatioQueueキュヌの䜜成ず䜿甚を瀺したす。

Swift配列はvalue typeあり、コピヌ時にコピヌ copy on write されるため、マルチスレッドの倉曎に぀いお心配する必芁はありたせんが、特に配列が型クラスのオブゞェクトのプロパティである堎合、これに問題があるかどうかに぀いおフォヌラムにメッセヌゞがありたす。 したがっお、異なるスレッドで新しい芁玠を远加するずきにthread safe配列を保持する方法を瀺したす。



次に、各画像のフィルタリング操䜜を䜜成し、非同期実行のためにfilterQueueに远加したす。 フィルタヌ凊理が完了したら、結果のむメヌゞをfilteredImages配列に远加し、 completionBlockでappendQueueたす。ここで別の操䜜キュヌappendQueueを䜿甚したす。 completionBlock入力パラメヌタヌcompletionBlockなく、䜕も返したせん。

すべおのフィルタリング操䜜が完了するのを埅っお、フィルタリングされた画像配列を確認したす。



すべおの操䜜の実行時間は1.19秒です。これは、1぀の操䜜前のセクションを参照の実行時間に匹敵したす。 filterQueue 、 filterQueueキュヌで操䜜のマルチスレッド実行が行われたす。 Playgroundは、フィルタリングされた画像の配列が衚瀺されたすが、フィルタリング効果を芋るには非垞に小さいです。 クむックビュヌボタンをクリックしお、フィルタリング効果を確認できたす。



非同期操䜜


コヌドはGithubの AsyncOperations.playgroundで衚瀺できたす。

これたでのずころ、SYNCHRONOUSタスクの操䜜、぀たり珟圚のスレッドを䜿甚し、タスクが完了するたで戻らない関数を䜿甚したした。 ASYNCHRONのタスク関数はたったく異なる方法で動䜜したす珟圚のスレッドですぐに制埡を返し、別のスレッドでタスクを実行し、タスクが完了したこずを知らせるため、他のスレッドでcompletionHandlerが閉じられたす。 兞型的な䟋はURLSessionです



Operation操䜜でURLSessionの機胜を「ラップ」できたすが、操䜜のステヌタスを手動で制埡する必芁がありたす。

SYNCHRONOUS関数のカスタム操䜜を䜜成するには、操䜜メ゜ッドmain()をオヌバヌラむドするだけで枈みたした。 ASYNCHRON関数でたったく同じこずを行う堎合、 main()ですぐに制埡を珟圚のスレッドに戻し、別のスレッドで動䜜するために「脱退」し、 main()メ゜ッドの最埌に移動し、 OperationQueueすぐにOperationQueueキュヌから「スロヌ」したす。 ASYNCHRON機胜を完了するこずはありたせん。 これがOperationQueue背埌にあるロゞックです。

非同期操䜜には、たったく異なる䜜業ロゞックがありたす。



操䜜が「準備完了」 isReady = true の堎合、OperationQueue操䜜キュヌはstart()メ゜ッドを呌び出したす。このメ゜ッドでは、操䜜を「running」状態 isExecuting = true に蚭定し、 main()メ゜ッドを呌び出したす。このメ゜ッドはASYNCHRON関数を呌び出したす。 ASYNCHRON関数はANOTHERスレッドで䜕かを行いたすが、 isExecutingプロパティは、CURRENTスレッドで䜕も行わず、別のスレッドで実行されおいるタスクのみを衚す堎合でもtrueたたでなければなりたせん。 ASYNCHRON関数がASYNCHRON関数のcompletionHandlerを瀺すcompletionHandler呌び出す堎合、 completionHandlerプロパティisFinishedをtrueに、 isExecutingプロパティをfalse蚭定する必芁がありfalse 。

したがっお、ASYNCHRON操䜜の堎合、 main()メ゜ッド以䞊のものをオヌバヌラむドする必芁がありたす。 次のメ゜ッドずプロパティをオヌバヌラむドする必芁がありたす。



Operationから継承され、ASYNCHRONOUS操䜜の実行に適した抜象カスタムクラスAsyncOperaton䜜成したしょう。 その抜象性は、非同期操䜜を実行するmain()メ゜ッドがないこずです。 圌の図は次のずおりです。



OperationQueueなしで自分でASYNCHRONOUS操䜜を䜿甚する堎合、 isAsynchronousプロパティをオヌバヌラむドしおtrueを返す必芁がありたす。 ASYNCHRON関数を実際に開始し、 isExecutingプロパティをtrue保぀には、 start()メ゜ッドをオヌバヌラむドする必芁がありたす。 たた、操䜜の状態を決定するプロパティisReady 、 isExecuting 、 isFinishedを管理する方法を孊ぶ必芁がありたす。 これらのプロパティは、 OperationQueue操䜜キュヌによっお䜿甚され、 OperationQueueのステヌタスを監芖し、䟝存する操䜜の実行を敎理したす。

操䜜間の䟝存関係を定矩する堎合、1぀の操䜜が別の操䜜を開始する前に終了する必芁があるため、 OperationQueue操䜜キュヌは、操䜜がい぀終了するかを知るこずが重芁です。 SYNCHRONOUS操䜜の堎合、SYNCHRONOUS機胜が終了するずSYNCHRONOUS操䜜が終了するため、これは問題ではありたせん。 ただし、ASYNCHRON関数は珟圚のスレッドの倖偎で終了するため、ASYNCHRON関数の実際の終了に぀いおOperationQueue操䜜キュヌに通知する方法が必芁です。 GCDを思い出すず、ASYNCHRONOUS関数をグルヌプに远加するずきに、 enter()およびleave()メ゜ッドを䜿甚しお、ASYNCHRONO関数の開始ず終了を明確に瀺したした。 ただし、Operation操䜜の堎合、操䜜にはisReady 、 isExecuting 、 isFinished 、 isCancelledなどの状態があるため、状況ははるかに耇雑ですisReady関数をOperation操䜜に远加する堎合、これらの状態を手動で管理する必芁がありたす。 この䜜業を容易にするために、 AsyncOperatonずいう名前のOperationクラスの特別な抜象ナヌザヌsubclassを䜜成したした。その䞻なタスクは、操䜜の状態の倉曎を制埡するこずです。 独自のASYNCHRON関数の堎合subclassクラスのsubclass䜜成し、そこからASYNCHRON関数を呌び出すmain ()のみを定矩したす。 そしお、すでにこの新しい操䜜はOperatonQueueに远加されOperatonQueue 。

ただし、問題は、たずえば、操䜜の状態に関連するすべおのプロパティisReady 、 isExecuting 、 isFinishedがreadonly  {get} であり、盎接蚭定できないため、 isExecuting = true蚘述できないこず{get} 。 AsyncOperaton操䜜のステヌタスAsyncOperaton倉曎されたこずをシステムに通知しながら、 isExecutingプロパティがtrue返すようにするこずしかできたせん。

Operationクラスは、 KVO  key-value observation メカニズムずwillChangeValueForKeおよびdidChangeValueForKeyをisReady 、 isExecuting 、 isFinished 、 isExecutingなどの状態プロパティの倉曎に぀いお通知したす。

したがっお、資産管理業務の䟿宜のために、私たちは、新しいデヌタ型を䜜成したす-適切な列挙enum State非同期操䜜独自の倉皮の状態を衚すためにready、executing、finished。


列挙Stateには、KVO通知のスむッチずしお䜿甚fileprivateする名前のプロパティも含たれたす。プロパティは蚈算され、倧文字の列挙芁玠の名前であるに接続された文字列で構成されたす。次に、抜象クラスで操䜜の珟圚の状態を衚す型倉数を定矩したす。デフォルトでは、この倀はequal です。倉数を倉曎するたびに、KVO通知を切り替える必芁がありたす。これを行うには、オブザヌバヌずプロパティを䜿甚したす。keyPathkeyPath"is"rawValueState

AsyncOperatonvar stateStatereadystatewillSet {}didSet {}state


stateたずえば、からexecutingに操䜜状態を切り替える前に、䞡方の操䜜の新しい状態ず珟圚の状態に぀いおKVO通知finishedを送信する必芁がありたす。切り替え条件が埌に発生した、我々は送信KVOの通知をするために䞡方の条件ず。これは、システムが新しい倀「ネむティブ」の状態倉数の読み出し動䜜をするようになりたす、、。そのため、非同期操䜜我々は「ネむティブ」状態倉数の操䜜を再定矩する必芁があり、、willChangeValuenewValuefinishedstateexecutingstatedidChangeValuekeyPatholdValueexecutingstatefinished

isReadyisExecutingisFinishedAsyncOperationisReadyisExecutingisFinishedstate正しい倀を返す蚈算倉数ずしお新しいプロパティを䜿甚したす。これをextensionクラス拡匵で行いAsyncOperationたす


ある時点で、操䜜のプロパティisReadyが等しくなりtrue、プロパティisReadyforを䜿甚する必芁がありたす。これは、他の操䜜superclassぞの䟝存性dependenciesを「知芚」したす。独自のロゞックずのプロパティisReadyを組み合わせるsuperclassこずで、操䜜が本圓に「準備完了」であるこずを確認できたす。泚倉数があればそれstateで.finished、のプロパティsuperclass isFinishedず同じtrue、ずプロパティisExecuting- false。たた、2぀のメ゜ッドをisAsynchronous返すこずでプロパティを再定矩したすtruestart()ずcancell()。

メ゜ッドでstart()は、操䜜が砎棄されおいるかどうか、぀たりプロパティisCancelledがequalであるかどうかを確認したすtrue。その堎合、倉数に新しい倀を蚭定する必芁がありたすstate- .finished。操䜜が砎棄されない堎合、を呌び出したすmain()。それは芚えおいるmain()非同期関数であり、それはすぐに戻りたすので、我々は手動操䜜の状況を蚭定する必芁がstat同じです.executing。 ASYNCHRON関数が戻るずき、completionHanller操䜜の状態を蚭定しなければなりたせん.finished。 ASYNCHRON関数の堎合、start()メ゜ッドでsuperclass-の同様のメ゜ッドの呌び出しを䜿甚できないこずを芚えおおくこずが非垞に重芁です。これはsuper.start()、関数の同期起動を意味し、main()正反察が必芁だからです。
このメ゜ッドでcancell()は、操䜜の状態も蚭定する必芁がありたす.finished。

その結果、抜象クラスを取埗したしたAsyncOperation、独自の非同期操䜜に䜿甚できたす。これを行うには、次の手順を実行したす。


䟋ずしお、sleep (1)2぀の数倀の非同期䜎速内郚にある加算の機胜を䜿甚したす。


AsyncOperationas を䜿甚しおsuperclass、再定矩main ()し、操䜜状態stateを.finishedin に蚭定するこずを忘れないでcallbackください


callbackリタヌンの結果result、我々はプロパティ操䜜割り圓お、self.resultおよびセット動䜜状態のstate時に.finishedこずを通知番号の非同期添加終了のすべおの操䜜をしお、もはやこの操䜜で䜜業する必芁がありたす。

を䜿甚しおSumOperation、数倀のペアの合蚈の配列を取埗したす。


数倀のペアごずSumOperationに、additionQueue通垞の方法で操䜜を䜜成し、操䜜のキュヌに配眮したす非同期操䜜の順序は、配列内の数倀のペアの順序ずはわずかに異なるこずがわかりたす。これは、非同期操䜜のマルチスレッド実行を瀺しおいたす。

第二の䟋は、䞎えられた画像の非同期ロヌディングに関するURL介しURLSession



非同期動䜜䜜成ImageLoadOperation前回のようにクラスのサブクラスです、、 AsyncOperation。操䜜に぀いおはImageLoadOperation、前回のように、再定矩main ()、および操䜜のステヌタスを蚭定するこずを忘れないでくださいstateäž­.finishedでcompletion



操䜜を䜜成しoperationLoad、画像を取埗operationLoad.outputImageし、䞊に衚瀺view



コヌドは、䞊で閲芧するこずができたすAsyncOperations.playgroundでのGithub。

䟝存関係dependencies


コヌドはGithubの LoadAndFilter.playgroundで衚瀺できたす。

このセクションでは、1぀の操䜜の結果を別の操䜜に転送し、最初の操䜜が終了したずきにのみ2番目の操䜜を匷制的に開始する方法を怜蚎したす。



図では、2぀の操䜜が衚瀺されたす。1぀目はネットワヌクから画像を読み蟌み、2぀目は画像の䞊郚ず䞋郚の「フォギング」を実行したす-フィルタリング。
これらの操䜜は䞡方ずも盞互に非垞にうたく機胜したす。むメヌゞの「ダりンロヌダヌ」はそのデヌタを「フィルタヌ」に盎接転送したす。

これらの䞡方の操䜜を含む1぀の操䜜を䜜成できたすが、これは非垞に柔軟な蚭蚈ではありたせん。



アプリケヌションのさたざたな堎所でむメヌゞを任意の順序で䜿甚するために、むメヌゞを操䜜する際に、操䜜のモゞュヌル性をある皋床確保するこずが望たしいです。

より柔軟な゜リュヌションは、最初の操䜜から2番目の操䜜ぞのむメヌゞの転送を䌎う操䜜の「チェヌン」の実装に関連付けられおいたす。 「フィルタヌ」は「ロヌダヌ」に䟝存しおいるず刀断でき、操䜜のキュヌはOperationQueue、「フィルタヌ」がready「ロヌダヌ」の終了埌にのみ状態に蚭定されるこずを認識したす。これは本圓に操䜜キュヌのすばらしい「胜力」ですOperationQueue。 「䟝存関係」の非垞に耇雑なグラフを䜜成しお、OperationQueue必芁に応じお自動的に操䜜を開始するこずができたす。「䟝存関係」の凊理をサポヌトAPIするクラスOperationdependencies-非垞にシンプルですが、操䜜䞭に玠晎らしい力を発芋したす。



「䟝存関係」dependencyを远加および削陀したりdependencies、この操䜜に远加された「䟝存関係」のリストを取埗したりできたす。以䞋では、リストdependenciesを䜿甚しお、䟝存フィルタリング操䜜の入力画像を取埗したす。

䟝存関係を䜜成するず、デッドロックdeadlockが発生する可胜性が高くなり



たす。「䟝存関係」列に閉じたルヌプが珟れるず、デッドロックが発生し、芖芚的な分析によっお特定する以倖に、それらを排陀する普遍的な方法はありたせん。
操䜜の「䟝存性」に関連する次の問題は、「䟝存性チェヌン」に沿っおデヌタを転送する方法です。たずえば、䞊蚘の䟋では、「ロヌダヌ」が最初に機胜し、次に「フィルタヌ」が機胜する堎合、入力むメヌゞは「ロヌダヌ」の出力むメヌゞになりたす。



これをどのように達成したすかこのImagePass堎合、必芁なデヌタを提䟛するプロトコルを䜜成したすUIImage? 



ロヌダヌ「 -すでにおなじみのクラスのImageLoadOperation圌は䞎えられた入り口にはネットワヌクのむメヌゞロヌド操䜜。URL文字列などの画像urlString、および出力-むメヌゞそのものoutputImage。



クラスImageLoadOperation」確認「プロトコルImagePassずプロトコルの特性を返すimage出力は画像を読み蟌たoutputImage。

タヌンでは、操䜜」フィルタリング「 -クラスをFilterOperation-入力画像が存圚しない堎合にはさ_inputImage䟝存性の確認」「dependenciesずだけ人々に興味を持っおいる」確認「レポヌトImagePass圌は䟝存ずしお第1の動䜜を遞択し、抜出物がそこ。inputImage



」フィルタ「を入力で-入力画像inputImage、出力は関数を䜿甚しおフィルタヌ凊理されたfilterImage (image:)画像outputImageです。これは通垞の同期操䜜なので、再定矩するだけで枈みたすmain()。

「フィルタヌ」inputImageが「ロヌド」操䜜の出力むメヌゞを入力むメヌゞずしお䜿甚するように、これら2぀の操䜜を連携させたいず思いたす。これを行うために、我々は、フィルタリングの動䜜を蚭定しfilterた倀でnil




コヌドが䞊に配眮されおいるLoadAndFilter.playground䞊のGithub。

䞊の操䜜の砎壊 OperationQueue


コヌドが䞊に配眮されおいるCancellation.playground䞊のGithub。

キュヌの別の玠晎らしいOperationQueue機䌚を芋おみたしょう-オペレヌションを砎壊する胜力。

操䜜Operationをキュヌに配眮した埌は、操䜜をOperationQueue実行するための独自の蚈画があり、操䜜を完党に制埡するため、操䜜を実行する方法はありたせん。ただしOperation、メ゜ッドを䜿甚しお砎棄するこずができたすcancel()。



メ゜ッドを呌び出すcancel()ずすぐに操䜜が停止するず思うかもしれたせんが、そうではありたせん。このメ゜ッドcancel()は、isCancelled操䜜プロパティをに蚭定するだけtrueです。操䜜がただ開始されおいない堎合、デフォルトの方法start()操䜜の実行を蚱可せず、プロパティisFinishedをに蚭定したすtrue。あなたはオヌバヌラむドする堎合overrideの方法をstart()、あなたはあなたの胜力保存しなければならないstart()財産の取匕があれば、操䜜の実行を防止するためisCancelledに蚭定されおいるがtrue。そしお、抜象クラスを芋るず、AsyncOperationたさにそれを行っおいるこずがわかりたす。

さらに、main()操䜜メ゜ッドで、特に䜎速たたはリ゜ヌス集玄的な凊理を実行する前にisCancelled、操䜜が既に砎棄されおいるかどうかをプロパティでテストする必芁がありたす。操䜜が砎棄され、trueプロパティの倀が衚瀺された堎合、操䜜isCancelledを停止するために必芁なアクションを実行する必芁がありたす。操䜜の堎合Operationたずえば、画像倉換などのロヌカルで実行した堎合、操䜜を停止できたす。サヌバヌから画像をダりンロヌドするなど、ネットワヌクぞのアクセスに関連する操䜜の堎合、サヌバヌが結果を返すたでそのような操䜜を停止するこずはできたせん。

操䜜のさたざたな「ステップ」の間に「ロゞック」を远加しお、この操䜜を実行し続ける䟡倀があるかどうか、たたは操䜜をisFinished等䟡状態に蚭定する䟡倀があるかどうかを確認する必芁がありtrueたす。操䜜を削陀するように蚭蚈され

APIたクラスOperationは非垞に単玔で、2぀の䜍眮のみで構成されたす。


メ゜ッドを呌び出すcancel()- isCancelled操䜜プロパティをに蚭定しtrueたす。メ゜ッドが呌び出されたずきにこずに泚意するこずが重芁でありcancel()、プロパティisExecutingずisFinishedもで倉化falseし、trueそれぞれ。


操䜜がisCancelled = true終了せずに砎壊されるこずは完党に正垞ですisFinished = true。プロパティisCancelledは、停止する必芁があるこずを操䜜に䌝え、プロパティは、isFinished操䜜が既に停止しおいるこずをシステムに䌝えたす。

私たちの抜象非同期操䜜は、AsyncOperationメ゜ッドをオヌバヌラむドしcancel()、動䜜状態を蚭定する方法にstateし.finishedお、このような倉曎は、倉曎操䜜のプロパティを起こしisFinishedずisExecuting


キュヌOperationQueueはすべおの操䜜を砎棄できたす。


䟋ずしおいく぀かのカスタム操䜜を䜿甚しお、メ゜ッド呌び出しに正しく応答する操䜜を取埗する方法を芋おみたしょうcancel()。

コヌドが䞊に配眮されおいるCancellation.playground䞊のGithub。

操䜜にArraySumOperationは、inputArray敎数のペアで構成されるタプルの入力配列がありoutputArray、出力でそれらの合蚈の配列を圢成したす。



数倀の各ペアに察しお、Cancellation.playgroundslowAddのフォルダヌSourceにある「遅い」加算関数を䜿甚し、出力配列に远加したす。数倀の入力配列を蚭定し、操䜜を圢成し、操䜜キュヌに远加したすoutputArray

sumOperationqueueタむマヌを起動しsumOperationたすcancel()。これにより、メ゜ッド呌び出しに察する操䜜の反応を確認できる時間をさらに調敎できたす。さらに、操䜜にはcompletionBlock、タむマヌを停止しPlayground outputArray、操䜜をポむントしお終了したすPlayground



そのため、操䜜を完了するにはsumOperation5秒以䞊かかりたす。今呌び出すこずによっお開始した埌、2秒埌に、この操䜜を砎壊しようcancel ()



私たちは、予期しない結果を埗たした-操䜜がsumOperation完党に無砎壊操䜜が発生しおいない、実装されおいたす。問題は䜕ですかしかし、実際には、メ゜ッドcancel ()はプロパティisCancelledをtrueに蚭定するだけであり、操䜜の削陀に必芁なアクションは操䜜の開発者に委ねられたす。プロパティがにisCancelled蚭定されおいるずいう事実に察応する必芁がありたすtrue。出力配列に合蚈を远加する前に、操䜜が砎棄されるかどうかを確認したす。そしお、それが砎壊された堎合、サむクルを䞭断したす



再開したしょうPlayground



2秒より少し遅れお停止し、2぀の量を取埗したした.3番目の量を取埗しようずしたずきに、操䜜の砎壊に関するシグナルを取埗し、量のさらなる受信を停止したした。この䟋は、コマンドに察するナヌザヌ操䜜の応答を取埗する方法を明確に瀺しおいたすcancel ()。

タプル配列を介しお出力配列ルヌプを取埗するためにAnotherArraySumOperation別の関数が䜿甚される点で異なる別の操䜜を芋おみたしょうslowAddArray



前のケヌスずの違いは、タプル配列の芁玠を介したルヌプがmain()操䜜メ゜ッドではなく、別の関数であり、私たちにずっお難しいこずです操䜜が砎棄された堎合、サむクルを䞭断したす。しかし、非垞に掗緎されたものではありたすが、このような可胜性がありたす



関数の入力には、敎数slowAddArrayのinputペアの配列に加えお、匕数がありたすprogress。これはOptional、配列の凊理の深さを匕数ずしお取り、

Double(results.count) / Double(input.count

それを返す関数ですBool。これBoolにより、アレむの継続凊理が決定されたす。

方法でmain()操䜜AnotherArraySumOperation前の図では、関数にslowAddArray配列を枡したした。inputArray匕数はprogress、「テヌル」クロヌゞャヌずしお蚭蚈されおおり、progress印刷にプロパティを䜿甚したした。プロパティprogressはDoubleですので、100を乗算し、配列凊理の完了率ず操䜜の完了率を取埗したした。次に、操䜜の砎棄に察する応答を返したす。これは、配列の凊理を続行たたは䞭断する信号です。反応はプロパティの逆ですisCancelled。

盎前の操䜜を元に戻しSumOperation、新たな操䜜䞊AnotherArraySumOperation



非継続事業をした埌2秒、我々は同じ結果を埗た-我々だけ扱うこずができた2の配列に5- 操䜜が砎棄される前、぀たり40。

操䜜䞭断遅延を4秒に蚭定したす。5の配列の4぀の芁玠、぀たり80は、操䜜が砎棄さ



れる前に凊理されたした。個々の操䜜がプロパティに応答するため、砎棄できるこずを確認するこずが非垞に重芁です。しかし、この方法を䜿甚しお、個々の取匕の砎壊に加えお、あなたはキュヌ操䜜にすべお開始の操䜜を削陀するこずができたす方法を䜿甚しお

isCancelled

cancel ()OprationQueuecancellAllOperations。これは、単䞀の目的で機胜する䞀連の操䜜がある堎合に特に圹立ちたす。この目暙は、耇数の独立した操䜜を䞊行しお実行するこず、たたは次々に実行される䟝存操䜜のグラフにするこずです。これらの䞡方のケヌスを怜蚎したす。

パタヌン1.独立した操䜜のグルヌプず連携する


コヌドが䞊に配眮されおいるCancellationGroup.playground䞊のGithub。前のセクションで瀺し

た操䜜ず同じ結果が埗られるようにタスクを蚭定ArraySumOperationしたした。この操䜜はタプルの配列を受け取り、(Int, Int)スロヌ加算関数を䜿甚しslowAdd()お、タプルを構成する数倀の合蚈の配列を䜜成したす。入力配列のコンポヌネントのサむクルは内郚に隠されおいArraySumOperationたす。個別の非垞に単玔な型操䜜のグルヌプを䜜成したしょうSumOperation。操䜜は、SumOperation入力ペアの2぀の数倀を远加しinputPair、䜎速加算機胜を経由しおslowAdd()、結果を返したすoutput



普通のクラスを䜜成GroupAdd管理private運営のキュヌqueueず䞀連の操䜜をSumOperation入力配列のすべおのペアの合蚈を蚈算し、出力配列にoutputArrayタプルを配眮するためにInt, Int, Int )゜ヌスデヌタず結果で構成され



たすクラスのむンスタンスを初期化するずき、数倀GroupAddのinputペアの入力配列が圢成され、そこから型の挔算が圢成されSumOperationたす。completionBlock各挔算で、結果が出力に远加されたすアレむのoutputArray単䞀䞊で実行され、privateシリアルラむン操䜜appendOperationを避けるために競合状態を。

クラスは、すべおの䞀般的な操䜜があるOperationメ゜ッドをstart()、cancel ()、wait ()。、私たちは、「耇雑な操䜜」ずしおそれを考えるこずができるように

䜜成したす。EQ emplyarクラスGroupAdd数倀のペアの配列を入力に送りたす



startを実行しgroupAdd、1秒埅機しおcancel ()から、メ゜ッドを䜿甚しおすべおの加算操䜜を操䜜キュヌから削陀したす。結果ずしお、すべおの動䜜䜿甚の完了埌wait()に䜿甚するこずができないmain queueが、䞊にあるこずができるPlayground、我々は、出力配列を短瞮



結果は、䞊で閲芧するこずが可胜Playground CancelletionGroup.playgroundでのGithub。

パタヌン2.䟝存する操䜜のグルヌプず連携する


コヌドが䞊に配眮されおいるCancellationFourImages.playground䞊のGithub。

䟝存する操䜜のグルヌプずしお、既によく知られおいる盞互接続された操䜜のグルヌプを考えおみたしょうUI。ネットワヌクからのむメヌゞの読み蟌み、フィルタリング、倉曎です。クラスでシヌケンスを䞊べるようにしおくださいImageProviderにこれらの操䜜を管理したすOperationQueueメ゜ッドを䜿甚しおstart ()、wait ()ずcancel ()。

2぀の抜象操䜜぀たり、メ゜ッド実装を持たない操䜜main()がありたす。 1぀はすでに慣れ芪しんでいるASYNCHRONOUS操䜜であり、もう1぀は䟝存関係から入力むメヌゞAsyncOperationをImageTakeOperation抜出する操䜜です。に基づいおinputImagedependecies

AsyncOperation指定されたURLの「ネットワヌク」から画像をダりンロヌドする操䜜を䜜成したしょう。



この操䜜ImagePassは、受信した画像outputImageを操䜜のチェヌンに沿っおさらに送信するためのプロトコルを確認したす。

抜象操䜜は、この操䜜の初期化䞭に指定されおいない堎合、䟝存関係からImageTakeOperation入力むメヌゞinputImageを抜出し、シヌケンシャル操䜜のチェヌンでむメヌゞを転送するために䜿甚されるdependecies既知のプロトコルを䜿甚しお出力むメヌゞを「ピックアップ」できたすImagePass



抜象クラスImageTakeOperationをsuperclass操䜜ずしお䜿甚するず非垞に䟿利です䟝存操䜜のチェヌンに関䞎したす。たずえば、フィルタヌ操䜜の堎合Filter



たたは、「ヒップスタヌ」スタむルで画像を「゚ヌゞング」する操䜜の堎合PostProcessImageOperation



たたは、クロヌゞャヌを䜿甚しお環境に入力画像を「捚おる」操䜜の堎合ImageOutputOperation



クラスを芋おみたしょうImageProvider。通垞のクラスを䜜成しおImageProvider制埡するこずをprivateキュヌ操䜜operationQueue、および䞀連の操䜜dataLoad、filterおよびoutput䞎えられたから画像をロヌドするためのURL、フィルタ、それを回路に枡しcompletion



クラスはImageProvider、すべおの兞型的な動䜜の持぀Operationメ゜ッドをstart()、cancel ()、wait ()、私たちは、「耇雑な操䜜ずしお、それを考慮するこずができたす「。

4぀のクラスむンスタンスを䜜成したすImageProvider。



むメヌゞのロヌドを開始したす



操䜜の完了を埅機しおおり、4぀のむメヌゞを取埗したす



すべおの操䜜の継続時間は10秒をわずかに超えおいたす。

むメヌゞのロヌドを開始し、6秒埅っおcancel ()から、メ゜ッドを䜿甚しおすべおの操䜜を削陀したす。その結果、1番目、3番目、4番目の3぀の画像のみがダりンロヌドされたす



。結果はGithubのプレむグラりンドCancelletionFourImages.playgroundで衚瀺できたす。

パタヌン3. TableViewControllerずCollectionViewControllerの操䜜


プロゞェクトコヌドはGithubのフォルダヌOperationTableViewControllerにありたす。倚くの堎合、iOSアプリケヌションのテヌブルには画像が含たれおおり、その画像を受信するにはサヌバヌぞのアクセスが必芁です。たた、前のセクションで説明した「フィルタリング」などの受信画像に察する远加アクションが含たれる堎合がありたす。これにはかなりの時間がかかり、テヌブルをスムヌズにスクロヌルするには、画像を䜿甚したすべおの操䜜を倖郚で非同期に実行する必芁がありたす。前のセクションで瀺したクラスのアプリケヌションを芋おみたしょう。これは、ネットワヌクからむメヌゞをロヌドし、それをフィルタリングおよび倉曎するための盞互接続された操䜜のグルヌプにすでに銎染みのあるこずを実行したす。䟋ずしお、1぀だけで構成される非垞に単玔なアプリケヌションを考えたす

main queueImageProviderUI

Image Table View Controller、テヌブルセルは、むンタヌネットからダりンロヌドされたむメヌゞずブヌトプロセスを瀺す掻動の指暙が含たれおいるどの



こちらのクラスであるImageTableViewControllerスクリヌンのサヌビスフラグメントImage Table View Controller



クラスのモデルはImageTableViewController8぀の配列ですのURLを

  1. ゚ッフェル塔
  2. ノェネツィア-他のものよりもはるかに長くロヌドおよびフィルタリング
  3. スコットランドの城
  4. 北極-02
  5. ゚ッフェル塔
  6. 北極圏-16
  7. 北極-15
  8. 北極-12




ImageTableViewCell画像がロヌドされるテヌブルのセルのクラスは次のずおりです。



Public APIこのクラスは、画像のURLアドレスをimageURLString含む文字列です。しかし、等しくないように蚭定するず、画像のロヌドは行われず、「回転ホむヌル」の圢のむンゞケヌタのみが機胜し始めたす。ただし、既に䜕らかの方法でロヌドおよび凊理されたむメヌゞがあり、methodを呌び出しおいる堎合、ラむトアニメヌションを䜿甚しお画面䞊のこのセルに衚瀺したす。このクラスには、メ゜ッドに倀を割り圓おるず開始するアクティビティむンゞケヌタがありたす。画像は、セルずテヌブルの盞互䜜甚を担圓するデリゲヌトメ゜ッドにロヌドされたす。imageURLStringnilimageupdateImageViewWithImagespinnerimageURLStringtableView( _ : cellForRowAt:)

UITableViewDelegateUITableViewCellUITableView 





このメ゜ッドを可胜な限り「促進」するために、クラスImageProviderを䜿甚した非同期むメヌゞの読み蟌みの芁求はメ゜ッドの範囲倖になりたすtableView( _ : cellForRowAt:)。tableView( _ : willDisplay:forRowAt:)デリゲヌトメ゜ッドに配眮され、セルが衚瀺されるように準備したす。別のtableView( _ : didEndDisplaying:forRowAt:)デリゲヌトメ゜ッドは、セルが画面を離れるたでに完了しないむメヌゞのダりンロヌド芁求を砎棄するために䜿甚されたす。これはかなり䞀般的なアプロヌチであり、動䜜するアプリケヌションで䜿甚できたすTableView。これにより、テヌブルのスクロヌルパフォヌマンスが向䞊したす。

しかし、最初に、ImageProviderこのアプリケヌションで䜿甚されるクラスに戻りたす。ImageProvider前のセクションで䜿甚されたクラスバリアントずは察照的にPlayground、簡略化された圢匏を䜿甚したす。぀たり、クラスのむンスタンスを初期化するずきImageProvider、isSuspended = true操䜜キュヌを停止しおからImageProvider、メ゜ッドを䜿甚しおクラスむンスタンスを具䜓的に開始する必芁はありたせん。start()初期化䞭に䟝存操䜜のチェヌンをすぐに開始し、waitUntilFinished等しく蚭定したす。falseこれはPlaygroundアプリケヌションではなく、同期メ゜ッドを䜿甚したすwait()。



したがっお、クラスImageProviderにはむニシャラむザがあり、その入力に、画像imageURLStringのURLずクラスのこのむンスタンスを䜜成した人に型の画像completionをgeneric返すClosure を含む文字列を指定する必芁がありたすUIImage?ImageProvider、蚈算されたプロパティを䜿甚する代わりにimage。入力回路completionには眲名がありたす(UIImage?) -> ()。぀たり、画像UIImage?を取埗し、䜕も返したせん。に戻るために䜿甚できたすUITableViewController。

さらに、クラスのむンスタンスの砎棄を蚱可する必芁がありたす。これにより、ImageProviderすべおの操䜜が完了する前にテヌブルセルが画面を離れるず、開始されたすべおの操䜜が砎棄されたす。したがっお、cancel()クラスにメ゜ッドがありImageProviderたす。

そのため、このクラスImageProviderは、サヌバヌからのむメヌゞのロヌド、フィルタリング、およびメ゜ッドぞの配信に関する䟝存操䜜のグルヌプの非同期実行を提䟛したすUITableViewDelegate。必芁に応じお、このクラスのむンスタンスを削陀できたす。

に戻るImageTableViewController。

メ゜ッドtableView( _ tableView:, cellForRowAt indexPath:)に画像をロヌドする代わりに、別のデリゲヌトメ゜ッドtableView( _ tableView: , willDisplay cell:, forRowAt indexPath:)でそれを行いたす- そしお、メ゜ッドの画像を削陀したすtableView( _ tableView: , didEndDisplaying cell:, forRowAt indexPath:)。これら2぀のメ゜ッドの

拡匵機胜extensionを䜜成したしょう。メ゜ッドから始めたしょうtableView( _ tableView: , willDisplay cell:, forRowAt indexPath:)。



メ゜ッドのtableView( _ tableView:, cellForRowAt indexPath:)ように、セルcellずindexPath。たず、暙準の手順に埓っお、セルのタむプがであるこずを確認しImageTableViewCellたす。次に、画像のURLずしおのimageProvider文字列imageURLs [ (indexPath as NSIndexPath).row ]ず、「テヌル」クロヌゞャヌずしお蚭蚈されたクロヌゞャヌを䜜成したす。クロヌゞャヌでは、このテヌブルセルに衚瀺する必芁がある画像を取埗したす。これは、曎新に䜿甚する必芁がありたすimageUImain queueなぜならUI、バックグラりンドキュヌbackground queueで曎新を行おうずするず、これは機胜せず、なぜこの画像が衚瀺されないのか䞍思議に思うからです。mainクラスプロパティがありたすOperationQueueがmain queue、必芁なセルを曎新するメ゜ッドupdateImageViewWithImage( image )を呌び出すmain queueだけUITableViewCellです。

ここで、操䜜の削陀の可胜性に぀いお考える必芁がありたす。これを行うには、䜜成されたものぞのリンクを倱う必芁はありたせんimageProvider。そうしないず、埌でそれを芋぀けお、それに関連付けられおいる操䜜を削陀できたせん。

私たちは、クラスの先頭に移動ImageTableViewControllerし、Cずいう名前の新しいプロパティを远加imageProviders



プロパティは、imageProviders型のオブゞェクトの集合でありimageProvider、最初は空です。

ImageProvider.swiftファむルの䞋郚を芋おみたしょう。あなたは、既存の拡匵すでにそこにあるでしょうextensionクラスImageProviderプロトコルを確認し、Hashableセットに必芁なのSet



私たちは、蚈算プロパティを取埗hashValueず平等のための比范挔算子を==。これで、オブゞェクトのむンスタンスをむンストヌルしお比范できたすImageProvider。に戻るImageTableViewController。これで、オブゞェクトのむンスタンスを远跡ImageProviderし、imageProviders珟圚アクティブなセットにそれらを远加できたす。



このコヌドを芋お、䜕が起こっおいるかを段階的に確認しおみたしょう。これはデリゲヌトメ゜ッドですtableView、セルが画面に衚瀺される盎前に呌び出されたす。この時点で、ImageProvider非同期的に読み蟌み、画像をフィルタリングし、結果の画像imageをに返すものを䜜成しcompletionHandlerたす。のimage曎新UIImageViewに䜿甚しmain queueたす。その埌、埌で砎壊できるようImageProviderに、倚数で蚘憶しimageProvidersたす。これは、次のデリゲヌトメ゜ッドtableViewでtableView( _ tableView:, didEndDisplaying cell:, forRowAt indexPath:)、セルが画面を離れた盎埌に呌び出される名前で行いたす。それは私たちがこのすべおの操䜜を砎壊する必芁があるこずをここにあるImageProvider



これを行うには、私たちが芋぀けImageProviderセル甚cell及び方法を䜿甚cancel ()するにImageProvider、このプロバむダヌのすべおの操䜜を削陀しおから、プロバむダヌ自䜓をsetから削陀したすimageProviders。い぀ものように、最初に暙準手順を実行しお、セルのタむプがであるこずを確認しおから、このセルImageTableViewCellず同じ行を持぀すべおのプロバむダヌを芋぀けたすImageURLString。これらすべおのプロバむダヌを調べお削陀し、セットから削陀したすimageProviders。それが私たちがする必芁があるすべおです。

アプリケヌションを実行したしょう。



画像の読み蟌み䞭にアクティビティむンゞケヌタが動䜜し、スクロヌルが遅延なく非垞に高速に動䜜するようになりたした。画像はロヌドされるたで空で、アニメヌション化されたす。玠晎らしい。
プロゞェクトコヌドはGithubのフォルダヌOperationTableViewControllerにありたす。

Operation OperationQueue GCD


GCDそしおOperations、圌らがどのように異なるかが、衚ショヌでは、䌌たような機胜の倚くを持っおいたす。



DispatchGroupそしお、OperationQueueそれらはすべおのタスクの完党な完了に関連するむベントを凊理できたすがwaitUntilAllOperationsAreFinished、キュヌのメ゜ッドを開始するずきは非垞に泚意する必芁がありOperationQueueたすmain queue。

䟝存関係dependeciesに関しおGCDは、タスクのチェヌンをprivate順次serialに実装するだけDispatchQueueです。しかし、これは最も匷い偎面OperationQueueです。䟝存関係dependeciesOperationQueueは単なるチェヌンよりも耇雑になる可胜性があり、異なるキュヌで操䜜を実行できたすOperationQueue。

でバリアを䜿甚できたすGCDシヌケンシャルserialキュヌがDispatchQueue適切でない堎合の「ラむタヌ」ず「リヌダヌ」の問題を解決する。を䜿甚しおこの問題を解決する適切な方法はOperationQueue非垞に玛らわしく、flags非垞に特別な䟝存関係が必芁です。

でGCDのみ削陀できDispatchWorkItemsたす。Operations独自のメ゜ッドを䜿甚しお操䜜を削陀するこずもcancel()、すべおの操䜜をすぐに削陀するこずもできたすOperationQueue。で短絡を削陀できBlockOperationたす。

ずの䞡方GCDでOperations、SYNCHRONOUS機胜を非同期的に実行できたす。そうするこずで、この操䜜Operationは、実装を含め、この再利甚可胜な機胜のすべおのデヌタをカプセル化するためのオブゞェクト指向モデルを提䟛したすsubclasses Operation。しかし、倚くの堎合、耇雑な䟝存関係を持たない単玔なタスクの堎合はGCD、操䜜を䜜成するよりも「軜い」メ゜ッドを䜿甚する方が䟿利Operationです。さらに、DispatchブロックのGCD完了に芁する時間は、ナノ秒からミリ秒たでで、Operation通垞は数ミリ秒から数分かかりたす。

おわりに


この蚘事では、操䜜に関する以䞋の質問を考慮し、Operationか぀キュヌ操䜜OperationQueue



1.操䜜がOperation問題ず「ラむフサむクル」ずそのステヌタスを衚瀺するプロパティを持぀1぀のオブゞェクト内のデヌタをカプセル化するこずができたす。

2. BlockOperationオブゞェクト指向の「ラッパヌ」DispatchQueue.global()であり、そのグルヌプの制埡を倱うのではなく、クロヌゞャヌのグルヌプの実行を远跡できたすDispatchQueue.global()。すでにアプリケヌションで䜿甚しおいお、それらに干枉したくない堎合はBlockOperation、代替ずしお単玔な操䜜に䜿甚するず䟿利です。3.運甚が開始されるず、その䞻な可胜性が明らかになりたすGCDOperationsDispatchQueue

OperationOperationQueue。操䜜を準備したらOperation、それをOperationQueueに枡したす。これは、すべおの操䜜の実行順序を制埡したす。これは、本質的に非垞に単玔なモデルであり、マルチスレッドプログラミングの耇雑さを隠したす。OperationQueueに䌌おDispatchGroupおり、異なるレベルの操䜜を組み合わせおqualityOfService、すべおの操䜜が完了するたで埅぀こずができたす。ただし、このsyncメ゜ッドを呌び出すずきは非垞に泚意する必芁がありたす。

4.操䜜にASYNCHRON関数を含めるにはOperation、その完了を正確に蚘録するために特別なこずをする必芁がありたす。KVOAsyncOperationを䜿甚しおASYNCHRON操䜜を手動で管理する必芁がありたす。5.比類のない操䜜

Operationそれらを䞀連の操䜜に組み合わせお、耇雑な䟝存関係グラフdependenciesを䜜成できるずいうこずです。これは、Operation1぀以䞊の他の操䜜Operationが完了するたで開始できない操䜜を非垞に簡単に識別できるこずを意味したす。この蚘事では、プロトコルprotocolを䜿甚しOperationお、䟝存関係グラフdependenciesの操䜜間でデヌタを転送する方法を瀺したす。ただしdeadLock、特に異なる操䜜の操䜜間に䟝存関係がある堎合は、解決できないデッドロックを匕き起こす可胜性のあるサむクルを回避するために、䟝存関係グラフを調査する必芁がありたすOperationQueue。

6.操䜜Operationを操䜜キュヌに転送したらOperationQueue、タヌンOperationQueue自䜓が実行のための操䜜を開始するためのスケゞュヌルを䜜成し、その実行を制埡するため、この操䜜の制埡を倱いたす。ただし、メ゜ッドcancel ()を䜿甚しお、操䜜が開始されないようにするこずができたす。この蚘事ではisCancelled、操䜜の構築時にプロパティを考慮するOperation方法ず、操䜜キュヌのすべおの操䜜を完党に削陀する方法を瀺したすOperationQueue。

7.結論は、むンタヌネットから取埗した画像でテヌブルをスクロヌルする必芁があり、「フィルタリング」や「゚ヌゞング」などの远加アクションが必芁な堎合の実際のシナリオを反映するアプリケヌションの開発を瀺しおいたす。これにはかなりの時間がかかり、テヌブルをスムヌズにスクロヌルするには、画像を䜿甚したすべおの操䜜を倖郚で非同期に実行する必芁がありたすmain queue。このアプリケヌションでは、操䜜Operation、特に非同期操䜜AsyncOperationずその䟝存関係dependenciesを操䜜するための幅広い技術を䜿甚したした。これにより、倧幅な改善を達成するこずができたしたUI。

䞀緒にこの蚘事で、以前のギブあなたの䞭にマルチスレッド凊理の党䜓像Swift 3ず4今存圚しおいるiOSの䞊、。安定性に加えお、マルチスレッドがSwiftバヌゞョンのSwift 5優先順䜍ABIずしお宣蚀されおいる堎合、珟圚敷蚭されおいるマルチスレッド凊理の将来の可胜性の議論に党面的に参加できたすconcurrency。バヌゞョンSwift 5完党に新しいマルチスレッドモデルの䜜業の開始のみが含たれ、その実装は将来のバヌゞョンでも継続されたす。Swift 5には、将来のマルチスレッドモデルの提案が既にありたす。だから「モヌタヌを぀けろ」そしお行っおください。

Swiftの進化はここで芋るこずができたす。

参照資料


→ WWDC2015。高床なNSOperationsセッション226。
→ iOSのNSOperationsをお楜しみください
→ SwiftのNSOperationずNSOperationQueueのチュヌトリアル
→ GCDずOperationsのiOS同時実行性
→ IOSの 䞊行性
→ Swiftの同時実行性1぀の可胜なアプロヌチ

Source: https://habr.com/ru/post/J335756/


All Articles