[Swift]async/awaitを使った実装のお勉強

初めに


この記事は、以下の記事を自分で学び直した記事です。

用意する関数

public func data(from url: URL, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)

    - Parameter url: The URL for which to load data.
    - Parameter delegate: Task-specific delegate.
    - Returns: Data and response.

・Paramater url:読み込みたいURLのデータ
・Paramater Delegate:具体的なタスクのdelegate
・Returns:データとレスポンスの型(戻り値)

上記のような関数が、Appleには標準で用意されている。

そのため、呼び出したければ、

let (data, _) = try await URLSession.shared.data(from: url)

みたいな書き方をしてあげると良い。

コードを実装していく(APIClient編)

NetWorking.swift

class Networking {
    static func request<D: Decodable>(url: URL, type: D.Type) async throws -> D {
        //読み込みたいURLからURLリクエストを取ってきてあげる。
                 var request = URLRequest(url: url)
        //進研ゼミでみたところ
        let (data, _) = try await URLSession.shared.data(for: request)
                 //とってきたdataをJSON形式にdecodeして返す //nilの時の処理したほうがいいかも
        return try JSONDecoder().decode(D.self, from: data)
    }
}

Article.Swift

//Article構造体を作る

struct Article: Decodable {
    let id: String
    let title: String
}

ArticleDetail .Swift

//Articleと同様にArticleDetailを作る

struct ArticleDetail: Decodable {
    let title: String
    let body: String
}

APIClient .Swift

//APIClientクラスを作る

class APIClient {
//baseURL
    private static let baseURL = "https://qiita.com"

//APITypeのenum(列挙型)
    private enum APIType  {
        case articles(Int)
        case articleDetail(String)

//Pathが Articlesだったら上のURLを、articleDetailだったら下のURLを返す
        var path: String {
            switch self {
            case .articles(let perPage):
                return "/api/v2/items?per_page=\(perPage)"
            case .articleDetail(let itemId):
                return "/api/v2/items/\(itemId)"
            }
        }

//URLはbaseURL+pathで返す。baseURLはprivateなのでAPIClientを明示する。
        var url: URL {
            URL(string: APIClient.baseURL + path)!
        }
    }


    /// 記事一覧取得 
    func fetchArticles(perPage: Int = 1) async throws -> [Article] {
        try await Networking.request(url: APIType.articles(perPage).url, type: [Article].self)
    }

    /// 記事詳細取得 
    func fetchArticleDetail(itemId: String) async throws -> ArticleDetail {
        try await Networking.request(url: APIType.articleDetail(itemId).url, type: ArticleDetail.self)
    }

}


コードを実装していく(呼び出し編)

ArticleViewModel.swift

class ArticleViewModel {

//APIClient型の変数apiClientを宣言
    private let apiClient: APIClient

//初期化
    init(apiClient: APIClient = APIClient()) {
        self.apiClient = apiClient
    }

//update()関数 - APIClientから記事を取得する。
    func update() {
        Task {
            do {
                let articles = try await self.apiClient.fetchArticles()
                print(articles)
                guard let id = articles.first?.id else {
                    return
                }
                let article = try await self.apiClient.fetchArticleDetail(itemId: id)
                print(article)
            } catch {
                print(error)
            }
        }
    }
}


自分でコードを読み直したら、なんとなく動きが理解できてきました。いつかRubyで自作APIを作ってそれをSwiftで受け取る、みたいなこともしてみたいですね。

いいなと思ったら応援しよう!