5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

withAdvent Calendar 2021

Day 11

Alamofire+Codableをasync/awaitを使ってリクエストする

Last updated at Posted at 2021-12-10

Swiftにも5.5でついにSwift Concurrencyが導入されたので一番有用そうなAPI取得周りをasync/awaitで記述できるようにしてみます。
今回はSwiftの通信ライブラリとしてスタンダードであろうAlamofire+Codableを環境として用いて実装しています。

(そのうちAlamofire公式にもasync/awaitで受け取れる口は出来るとは思いますが現時点ではiOS15以降が要求されるのでしばらくは入らないかと思います)

AlamofireのExtensionを記述する

Alamofireはクロージャで結果を受け取とれるので、これをasync/awaitに変換します。
旧来のクロージャ構文を変換するにはwithCheckedThrowingContinuationを利用します。

DataRequestExtension.swift
import Foundation
import Alamofire

extension DataRequest {

    func publish<T>(_ type: T.Type) async throws -> T where T : Decodable {
        try await withCheckedThrowingContinuation { continuation in
            self.response { response in
                switch response.result {
                case .success(let element): do {
                    let decodedResponse = try JSONDecoder().decode(type, from: element!)
                    continuation.resume(returning: decodedResponse)
                } catch {
                    continuation.resume(throwing: error)
                }
                case .failure(let error):
                    continuation.resume(throwing: error)
                }
            }
        }
    }
}

continuation.resumeを呼ぶことで呼び出し元へ結果を返して処理をすすめる事ができます。

実際に呼び出してみる

あとは生やしたメソッドを呼び出すだけでasync/awaitへの変換は完了します。
普段どおりCodableを実装したstructを用意してください。

GithubUser.swift
import Foundation

struct GithubUser: Codable, Equatable, Identifiable {
    let id: Int
    let name: String
    let htmlUrl: String
    let avatarUrl: String

    enum CodingKeys: String, CodingKey {
        case id = "id"
        case name = "name"
        case htmlUrl = "html_url"
        case avatarUrl = "avatar_url"
   }
}

その上で、Alamofireのリクエストクラスから作成したpublish()を呼びだしてください。

GithubApi.swift
struct GithubApi {
    func fetchUser(userName: String) async throws -> GithubUser {
        try await AF.request("https://api.github.com/users/\(userName)").publish(GithubUser.self)
    }
}

withCheckedThrowingContinuationとwithCheckedContinuation

上記ではクロージャの変換用にwithCheckedThrowingContinuationを紹介しましたが、
これとは別に withCheckedContinuationという関数もあります。
こちらはErrorをThrowすることがない場合に利用できます。こちらの関数ではtryの指定が不要になるので処理が失敗しうるかどうかで使い分けてください!

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?