iOS13に出てきたSwiftUI・Combineと、ライブラリのAPIKitを使い、通信部分の実装手法を紹介したいと思います。
今回は、GitHub APIを使用します。
どのようなアプリを作るか
以下のようなアプリを作ります。
リポジトリ名を入力し、結果を一覧で取得します。
実装のポイント
- できるだけシンプル:冗長なコードはなるべく書かない
- 保守性がある:読みやすいコード
- 再利用性がある:別の異なるAPIでも少しの変更で利用が可能
開発環境・使用するライブラリなど
開発環境
- OS:10.15.6
- Xcode:10.6
- iOS:iOS13以降(iOS14では確認していません)
使用するライブラリ
APIKit
今回は、APIKitを拡張し、CombineのPublisherでAPIを叩いた結果を取得します。
使用するフレームワーク
- SwiftUI
- Combine
また、Swift標準のDecodableを使い、JSONをパースします。
使用する考え方
- リポジトリパターン:APIやDBにアクセスするための定義を抽象化
実装
全体像
- ContentView:UI表示
- GitHubSearchModel:ロジックを管理するクラス
- GitHubRepository:APIへのアクセス方法を定義
API基本部分
API部分のクラス相関図は以下のようになります。
GitHubRepository.swiftについては、中身は以下のようになっています。
import Foundation
import APIKit
class GitHubRepository {
//GitHubレスポンス用のデコーダー
static let decoder: GitHubDecoder = .init()
//リポジトリを検索
struct SearchRepositories: GitHubRequestProtocol {
//https://developer.github.com/v3/search
//検索クエリ
let query: String
let method: HTTPMethod = .get
let path: String = "/search/repositories"
var decoder: JSONDecoder {
return GitHubRepository.decoder
}
var params: [String: Any] {
return [
"q": query
]
}
typealias Response = SearchResponse
}
private init() { }
}
GitHubRepository
はリポジトリなので、APIアクセスに必要な情報だけを定義(抽象化)しています。
SearchResponseはDecodableに準拠しています。
GitHubRequestProtocol.swiftとGitHubDecoder.swiftとAPIDataParser.swiftはソースをご確認ください。
ここまでで、GitHub APIを叩くための準備ができました。
Modelの実装
GitHub APIを使い、情報を取ってくるロジック(モデル)を実装します。
今回はViewとしてSwiftUIを使用するので、ロジックはObservableObjectを継承したクラスにします。
/// 検索モデル
class GitHubSearchModel: ObservableObject {
@Published var items: [SearchItem] = [] //検索結果
・・・・
/// 検索を行う
func search() {
debugPrint("search")
// 1)APIリクエストを作成
let request = GitHubRepository.SearchRepositories(query: searchText)
// 2)CombineのPublisherを作成し、通信処理を行う
self.requestCancellable = request.publisher //Publisherに変換(この時点で通信処理を行なっている)
.receive(on: DispatchQueue.main) //メインスレッドで受け取る
.sink(receiveCompletion: { result in
・・・・
}, receiveValue: { [weak self] response in
// 3)結果をitemsに保存
self?.items = response.items
})
// 4)itemsの更新はCombineを通して通知される
}
- APIリクエストを前述のリポジトリから作成します。
- 通信処理を行います。
- 結果を
items
に格納します -
items
の変更はCombineによりUIに通知されます。
UI
ContentView
こちらをご確認ください。
ソースコード
今回のソースコードはこちらに置いてあります。
https://github.com/usk-lab/APIKitCombine
再利用性について
今回はGitHub APIを使用しました。
GitHubRepository
, GitHubRequestProtocol
, GitHubDecoder
を少し変えることで他のAPIサービスでも利用できます。
参考
- https://github.com/ishkawa/APIKit/
- https://developer.github.com/v3/search/
- https://qiita.com/woxtu/items/ec689cf7709c3ce7d954
- https://qiita.com/renchild8/items/6cdaaad52c900f6efd38
- https://qiita.com/sgr-ksmt/items/e822a379d41462e05e0d
- https://dev.classmethod.jp/articles/rxswift-apikit-decodable-incremental-search/
- https://dev.classmethod.jp/articles/ios13-swiftui-combine-incremental-search/