SwiftでObjective-Cスタイルの非同期APIを使用
3837 ワード
作者:Ole Begemann,原文リンク,原文日付:2017-01-19訳者:Cwift;校正:walkingway;原稿:CMB
多くのObjective-Cスタイルの非同期APIは、オペレーションが成功したときのメソッドの戻り値を表し、オペレーションが失敗したときに返されるエラー値を表す2つのオプションタイプの値をコールバック閉パケットに入力します.
一例はCore LocationフレームワークのCLGeocoderである.reverseGeocodeLocationメソッド.CLLocationオブジェクトを受け入れ、座標情報をWebサーバに送信すると、サーバは座標を読み取り可能なアドレスに解析します.ネットワーク要求が完了すると、このメソッドはコールバック閉パケットを呼び出します.パラメータはCLPlacemarkオブジェクトを格納するオプションの配列と、選択可能なErrorオブジェクトです.
Objective-CスタイルのAPIでは、選択可能な成功値とエラーのペアを返すモードが、このような状況を処理する際に最も実用的なスキームである.
現在のAPIの問題は、実際には、要求が成功して結果を返すか、失敗してエラーを返すかの2つの可能性しかありません.しかし、このコードは4つの異なる状態を可能にします.結果は空ではなく、エラーは空です. エラーは空ではなく、結果は空です. 両方とも空ではありません. 両方が空です.
APIのドキュメントは、最後の2つの状況を明確に排除できますが、ユーザーとしては、ドキュメントが正しいことを確実にすることはできません.
Swiftでは、このように同じAPIを設計することができます.
コールバック閉パケットには、
この架空の新しいAPIを使用すると、コンパイラは、コールバック閉パケットに渡されるパラメータが成功または失敗の2つの状態しかないことを保証できます.両方の値が存在するか、存在しないかを心配する必要はありません.
しかし,アップルのAPIを修正することはできないので,コールバック閉パケットにおけるパラメータ固有の曖昧性には力がない.オプションの成功値とオプションのエラーを単一の
両方の入力が
追加の1行のコードを使用して、パラメータを
2017年1月20日の更新:Shawn Throopは、前述した
本文はSwiftGG翻訳グループから翻訳して、すでに作者の翻訳の授権を得て、最新の文章は訪問して下さいhttp://swift.gg.
多くのObjective-Cスタイルの非同期APIは、オペレーションが成功したときのメソッドの戻り値を表し、オペレーションが失敗したときに返されるエラー値を表す2つのオプションタイプの値をコールバック閉パケットに入力します.
一例はCore LocationフレームワークのCLGeocoderである.reverseGeocodeLocationメソッド.CLLocationオブジェクトを受け入れ、座標情報をWebサーバに送信すると、サーバは座標を読み取り可能なアドレスに解析します.ネットワーク要求が完了すると、このメソッドはコールバック閉パケットを呼び出します.パラメータはCLPlacemarkオブジェクトを格納するオプションの配列と、選択可能なErrorオブジェクトです.
class CLGeocoder {
...
func reverseGeocodeLocation(_ location: CLLocation,
completionHandler: @escaping ([CLPlacemark]?, Error?) -> Void)
...
}
Objective-CスタイルのAPIでは、選択可能な成功値とエラーのペアを返すモードが、このような状況を処理する際に最も実用的なスキームである.
2つの可能な結果、4つの潜在的な状態
現在のAPIの問題は、実際には、要求が成功して結果を返すか、失敗してエラーを返すかの2つの可能性しかありません.しかし、このコードは4つの異なる状態を可能にします.
APIのドキュメントは、最後の2つの状況を明確に排除できますが、ユーザーとしては、ドキュメントが正しいことを確実にすることはできません.
Resultによる優れた設計
Swiftでは、このように同じAPIを設計することができます.
class CLGeocoder {
...
func reverseGeocode(location: CLLocation,
completion: @escaping (Result) -> Void)
...
}
コールバック閉パケットには、
Result<.../>
のタイプの1つの(非選択)パラメータしか受け入れられません.Result
は、SwiftのOptionalタイプと非常に似ている列挙である.唯一の違いは、エラー値を失敗時に保存できますが、Optional
は成功時の関連値のみです.enum Result {
case success(T)
case failure(Error)
}
Result
は現在、Swift標準ライブラリのメンバーではありませんが、将来導入される可能性があります.その前に、自分で定義するのも簡単です.あるいは、現在流行しているantitypical/Resultライブラリを使用することができます.(注:このライブラリのResult
は、私がここで使用しているタイプとは少し異なります.強いタイプのエラーを使用しています.つまり、2番目の汎用パラメータがエラーのタイプを表しています.)この架空の新しいAPIを使用すると、コンパイラは、コールバック閉パケットに渡されるパラメータが成功または失敗の2つの状態しかないことを保証できます.両方の値が存在するか、存在しないかを心配する必要はありません.
1つのハンドル(T?,Error?)Resultに変換されたコンストラクタ
しかし,アップルのAPIを修正することはできないので,コールバック閉パケットにおけるパラメータ固有の曖昧性には力がない.オプションの成功値とオプションのエラーを単一の
Result
値に変換する論理を含むことができます.コードでResult
の便利なコンストラクタを定義しました.import Foundation // needed for NSError
extension Result {
///
/// Result 。
/// API Result。
init(value: T?, error: Error?) {
switch (value, error) {
case (let v?, _):
//
self = .success(v)
case (nil, let e?):
self = .failure(e)
case (nil, nil):
let error = NSError(domain: "ResultErrorDomain", code: 1,
userInfo: [NSLocalizedDescriptionKey:
"Invalid input: value and error were both nil."])
self = .failure(error)
}
}
}
両方の入力が
nil
(通常は発生すべきではない)の場合、カスタムエラーを作成して結果に入れます.ここではNSErrorを使用していますが、Error
プロトコルを遵守しているタイプを使用することができます.このコンストラクタを定義した後、地理エンコーダのAPIを以下のように使用します.let location = ...
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(location) { placemarks, error in
// Result
let result = Result(value: placemarks, error: error)
// result
switch result {
case .success(let p): ...
case .failure(let e): ...
}
}
追加の1行のコードを使用して、パラメータを
Result
タイプの値に変換します.その時から、未処理の心配はありません.2017年1月20日の更新:Shawn Throopは、前述した
CLGeocoder
拡張のコードを最適化することをお勧めします.コードはResult
ベースのメソッドのみを呼び出します.このメソッドは、元のAPIを内部で呼び出し、タイプの変換を担当します.extension CLGeocoder {
func reverseGeocode(location: CLLocation,
completion: @escaping (Result) -> Void) {
reverseGeocodeLocation(location) { placemarks, error in
completion(Result(value: placemarks, error: error))
}
}
}
本文はSwiftGG翻訳グループから翻訳して、すでに作者の翻訳の授権を得て、最新の文章は訪問して下さいhttp://swift.gg.