はじめに
最近、 iOS開発、SwiftUI の勉強をしているのですが、WebAPI の呼び出しをするため Alamofire を選定しました。
非同期処理では Alamofire + RxSwift などを使用するのが一般的のようですが、Alamofire 5.2.0 で Apple 製の非同期ライブラリ Combine がサポートされましたので、 Alamofire + Combine を試してみました。
ライブラリ等
Xcode : 12.4
Alamofire : 5.4.1
サンプルアプリ
サンプルアプリとして、Chatwork API トークンを TextField に入力させ、値が取得できたら name に名前をセットして表示する、ミニマムなアプリを作成しました。
WebAPI は Chatwork API の /me を使用しています。
実装
import Foundation
import Combine
import Alamofire
class LoginViewModel: ObservableObject {
private var disposeBag = Set<AnyCancellable>()
@Published var token = ""
@Published var name = "name"
func getMe() {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
AF.request("https://api.chatwork.com/v2/me", headers: ["X-ChatWorkToken": token])
.publishDecodable(type: MeModel.self, decoder: decoder)
.sink { data in
guard let me = data.value else {
print("error")
return
}
print(me.name)
print(me.accountId)
self.name = me.name
}.store(in: &disposeBag)
}
}
.publishDecodable(type: MeModel.self, decoder: decoder)
が DataResponsePublisher を返却するため、Combine で扱うことができるようになります。
Chatwork API のレスポンスは、 key がスネークケースaccount_id
ですが、Swift ではキャメルケースaccountId
ですので、
decoder.keyDecodingStrategy = .convertFromSnakeCase
で、変換するように指定しています。
Decodableを実装したデータモデルの定義
自分自身の情報を表すデータモデルは以下のように定義しました。
データの定義 MeModel.swift
import Foundation
struct MeModel: Decodable {
var accountId: Int
var roomId: Int
var name: String
var chatworkId: String
var organizationId: Int
var organizationName: String
var department: String
var title: String
var url: String
var introduction: String
var mail: String
var telOrganization: String
var telExtension: String
var telMobile: String
var skype: String
var facebook: String
var twitter: String
var avatarImageUrl: String
var loginMail: String
}
参考までに、UIの定義はこんな感じです。
UIの定義 ContentView.swift
import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel = LoginViewModel()
var body: some View {
NavigationView {
VStack(alignment: .center) {
VStack(alignment: .leading) {
Text("Token")
TextField("token", text: $viewModel.token, onCommit: {
})
.keyboardType(.alphabet)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.horizontal)
Text(viewModel.name)
}
.padding(10)
Divider()
Button("Get") {
viewModel.getMe()
}
.padding()
}
.overlay(RoundedRectangle(cornerRadius: 5).stroke())
.padding(.horizontal, 50)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Moya は Combine に対応していない
ちなみに、Alamofire をより簡単に利用するための Moya というライブラリがありますが、14.0.0 では Combine にはまだ対応していません。
14.0.0 beta で一度導入されたものの、問題があってリリース前に消えたようです。