2017-04-10 10 views
3

私は非同期的に、このように派遣キューを使用したテストでいくつかの機能を実行しています:Swift 3で非同期クロージャからエラーをスローする方法はありますか?

let queue: DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated) 
let group: DispatchGroup = DispatchGroup() 

func execute(argument: someArg) throws { 
    group.enter() 
    queue.async { 
    do { 
     // Do stuff here 
     group.leave() 
    } catch { 
     Log.info(“Something went wrong") 
    } 
    } 
    group.wait() 
} 

時には「やる」ブロック内のコードは、私が後にキャッチする必要があること、エラーを投げることができます。テストを開発しているので、 "do"ブロック内のコードがエラーをスローすると、エラーが発生します。 "queue.async"コールの中でエラーをキャッチせずにエラーをスローする方法はありますか?

答えて

0

queue.syncを使用するようにコードをリファクタリングしてからエラーを投げてください。例えば

(。あなたのexecute機能は、実際にそれは問題ないはず同期しているので)、DispatchQueueからこのメソッドを使用します。

func sync<T>(execute work:() throws -> T) rethrows -> T 

ところで、良いイディオムを出るときDispatchGroupは次のとおりです。あなたが誤ってWHEデッドロックはありません保証あなたの同期/非同期ブロックの最初の行として

defer { group.leave() } 

nエラーが発生します。

0

あなたはエラーを投げることはできませんが、エラーを返すことができます。

まず、あなたが同様にあなたの呼び出し関数を非同期に行う必要があります。

func execute(argument: someArg, completion: @escaping (Value?, Error?)->()) { 
    queue.async { 
    do { 
     // compute value here: 
     ... 
     completion(value, nil) 
    } catch { 
     completion(nil, error) 
    } 
    } 
} 

完了ハンドラは、どの我々は可能性パラメータを取りたとえば、値またはエラーのいずれかを含む「結果」​​があります。ここでは、タプル(Value?, Error?)があります。ここで、Valueはタスクによって計算されるタイプです。しかし、代わりに、これにはより便利なSwift Enumを活用することができます。 Result<T>またはTry<T>(ウェブを検索したい場合があります)。次のように

はその後、あなたはそれを使用します。

execute(argument: "Some string") { value, error in 
    guard error == nil else { 
     // handle error case 
    } 
    guard let value = value else { 
     fatalError("value is nil") // should never happen! 
    } 
    // do something with the value 
    ... 
} 

役立つかもしれないいくつかのルール:

  1. を関数は、内部で非同期関数を呼び出す場合、それは避けられないとしても、非同期関数となります。 *)

  2. 非同期関数には完了ハンドラが必要です(それ以外の場合は、「火災と忘れ」のようなものです)。

  3. 何があっても、完了ハンドラを呼び出す必要があります。

  4. 完了ハンドラが(呼び出し側に関して)非同期的に呼び出さなければなりません

  5. 機能を実行するために指定するパラメータを持っていない限り、完了ハンドラはプライベート実行コンテキスト(別名ディスパッチキュー)に呼び出されなければなりません完了ハンドラメインスレッドまたはメインディスパッチキューを使用しないでください。明示的にその事実をドキュメントに記述するか、意図的にデッドロックを危険にさらしたくない場合を除きます。

*)あなたは、呼び出し元のスレッドをブロックセマフォを使用してそれを同期させるためにそれを強制することができます。しかし、これは非効率的で、実際にはほとんど必要ありません。

これは多少面倒なようです。幸いにも、助けがあります - FutureまたはPromiseを探して、これをきちんとラップして、コードをより簡潔かつ分かりやすくすることができます。

注:ユニットテストでは、非同期呼び出し(XCTestフレームワークを参照)を処理するための期待を使用します。

関連する問題