はじめに
今回は自分用メモです。
質問などはコメントのところで受け付けています!
今回したいこと
closureを用いてServerの通信が完了した後、成功したらUIを更新、失敗したらエラーアラートを出す処理を作る。
ネットワークエラーが発生した時のエラー内容をenumで書き出しておく。
enum NetworkError: Error, CustomStringConvertible {
case unknown
case invalidResponse
case invalidURL
var description: String {
switch self {
case .unknown: return "不明なエラーです"
case .invalidResponse: return "不正なレスポンスです"
case .invalidURL: return "不正なURLです"
}
}
}
次に、APIClientというクラスに通信処理を保持させておく。
class APIClient {
func sendRequest(success: @escaping ([String: Any]) -> (), failure: @escaping (Error) -> ()) {
//リクエストするURL。実際には存在するURLを用いる。
guard let requestUrl = URL(string: "https://test") else {
//もしrequestUrlがnilだったら、invalidURLエラーをfailure closureに渡し、処理を終える。
failure(NetworkError.invalidURL)
return
}
//URLRequest、URLSessionを作成している。
let request = URLRequest(url: requestUrl)
let session = URLSession.shared
//Serverに対するリクエストを実行している。
let task = session.dataTask(with: request) { (data, response, error) in
if let error = error {
//もしエラーだったら、errorをfailure closureに渡し、処理を終える。
failure(error)
return
}
guard let data = data else {
//もしServerから何もデータが返ってこなかったら、unknownエラーをfailure closureに渡し、処理を終える。
failure(NetworkError.unknown)
return
}
//Serverから返って来たデータを辞書形式に変換する。
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
//変換できない場合、invalidResponseエラーをfailure closureに渡し、処理を終える。
failure(NetworkError.invalidResponse)
return
}
//jsonをsuccess closureに渡す。
success(json)
}
task.resume()
}
}
呼び出したい場所で以下のように記述すればServerに対してリクエストが成功した後、もしくは失敗した後特定の処理を記述できる。
let api = APIClient()
api.sendRequest(success: { (json) in
//success closureが来た時の処理(引数はjson)
//UIの更新
}) { (error) in
//failure closureが来た時の処理(引数はerror)
//エラーアラート
}
最後に
今回のclosureはコールバック関数みたいな使われ方をしてますね。