[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で受け取る、みたいなこともしてみたいですね。