Alamofire + Combine 사용

소개



최근, iOS 개발, SwiftUI 의 공부를 하고 있습니다만, WebAPI 의 호출을 하기 위해 Alamofire 를 선정했습니다.
비동기 처리에서는 Alamofire + RxSwift 등을 사용하는 것이 일반적인 것 같습니다만, Alamofire 5.2.0 에서 Apple제의 비동기 라이브러리 Combine 가 서포트되었으므로, Alamofire + Combine 를 시도해 보았습니다.

도서관 등



Xcode : 12.4
Alamofire : 5.4.1

샘플 앱



샘플 앱으로 ChatWork API 토큰을 TextField에 입력하고 값을 얻을 수 있으면 이름에 이름을 설정하여 표시하는 최소한의 앱을 만들었습니다.

WebAPI는 Chatwork API/me을 사용합니다.



구현



LoginViewModel.swift
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

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

MeModel.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를 보다 간단하게 이용하기 위한 모야 라고 하는 라이브러리가 있습니다만, 14.0.0 에서는 Combine 에는 아직 대응하고 있지 않습니다.
14.0.0 베타에서 한 번 소개되었지만 문제가 있고 출시 전에 사라진 것 같습니다..

좋은 웹페이지 즐겨찾기