얼마전 [Alamofire 사용법 - GET] 포스팅을 통해 Alamofire의 GET에 대해 다뤄보았다
그런데 더 전에 [async/await를 이용한 비동기 통신] 포스팅을 통해 다룬 async/await도 적용을 해볼 수 있지 않을까?? 하는 생각에 여기저기 찾아보니
Alamofire Github에 swift-concurrenc에 대해 다룬 파트가 있었다
사용하는건 URLSession을 이용할 때와 크게 다르진 않지만 AF를 사용할때의 장점은 여전히 있다(decoding, URL 등등)
다만 completion을 사용하는 AF와 다른 점은 dataTask를(URLSession과는 조금 다른) 사용 해야한다는 것이다
(하지만 여전히 URLSession보다는 간단하다)
func newRequest<T: Decodable>(api:APIable, resultType: T.Type) async throws -> T {
let baseURL = api.host + api.path
let request = AF.request(baseURL, method: api.method, parameters: api.params)
let dataTask = request.serializingDecodable(resultType)
switch await dataTask.result {
case .success(let value):
guard let response = await dataTask.response.response, (200...299).contains(response.statusCode) else {
throw APIError.responseError
}
return value
case .failure:
throw APIError.transportError
}
}
나는 데이터 요청을 하면서 Decoding도 같이 할 예정이기 때문에 serializingDecodable
이라는 메서드를 사용했으며 이 메서드를 통해 dataTask를 만들어준다
먼저 dataTask의 result를 확인해 통신과정에서 에러가 있는지 아닌지 판단을 한다
success 일때
failure 일때
private func getSearchInfo() {
self.startLoading.accept(())
let api = BookAPIModel(bookTitle: searchText, startIndex: startIndex, maxResult: maxResult, method: .get)
Task {
do {
let searchResult = try await networkManager.newRequest(api: api, resultType: SearchResult.self)
await MainActor.run {
guard let totalItems = searchResult.totalItems, totalItems != 0 else {
self.showAlert.accept("검색 결과가 없습니다")
self.totalItems.accept(0)
self.stopLoading.accept(())
return
}
self.totalItems.accept(totalItems)
let oldItems = items.value
let newItems = oldItems + (searchResult.items ?? [])
self.items.accept(newItems)
self.stopLoading.accept(())
}
} catch let error {
await MainActor.run {
self.showAlert.accept(error.errorMessage)
stopLoading.accept(())
}
}
}
}
호출부는 URLSession과 AF를 비교했을 때는 크게 달라진 점은 없다
AF의 completion handler와 acync/await를 비교했을 때는 아래와 같은 차이점이 있다
위 두 내용으로 정리를 해보자면 개인적으로 비동기 메서드는 UI업데이트가 되기 직전까지는 비동기로 진행되어야 최대로 효율을 낼 수 있지 않을까? 하는 입장으로 서는 async/await가 좋다고 생각이 들지만 불편하긴 한 것 같다 일일이 다 해줘야 하니...
그래도 비동기값을 completion을 사용하지 않고 return값으로 사용할 수 있다는건 엄청나게 큰 메리트라고 생각이 든다!