Async와 await을 사용하기
1. 기존의 코드
override func viewDidLoad() {
super.viewDidLoad()
self.getData { data in
self.decode(data: data) { contents in
print(contents) // "<!doctype html>~~~~
}
}
}
func getData(completion: (Data) -> Void) {
let url = URL(string: "https://zeddios.tistory.com")!
let data = try! Data(contentsOf: url)
completion(data)
}
func decode(data: Data, completion: (String) -> Void) {
let contents = String(data: data, encoding: .utf8)!
completion(contents)
}
2. completion과 메소드를 async로 전환
func getData() async -> Data {
let url = URL(string: "https://zeddios.tistory.com")!
let data = try! Data(contentsOf: url)
return data
}
func decode(data: Data) async -> String {
let contents = String(data: data, encoding: .utf8)!
return contents
}
3. 사용하는 쪽에서 await
func process() async {
let data = await self.getData()
let contents = await self.decode(data: data)
print(contents)
}
4. 해당 비동기를 사용할곳에 Task로 감싸서 붙이기
override func viewDidLoad() {
super.viewDidLoad()
Task {
await self.process()
}
}
Async await을 사용한 코드 예제
private func fetchUsers() async -> [User] {
guard let url = url else {
return
}
do {
let (data, _) = try await UrlSession.shared.data(from: url)
let user = try JSONDecoder().decode([User].self, from: data)
return user
}
catch {
return []
}
}
이러한 코드를 통해서 기존의
viewDidLoad() {
super.viewDidLoad()
fetchUsers() { users in
self.users = users
DispatchQueue.main.async {
self.tableView.reload()
}
}
}
이러한 코드를 다음과 같이 작성이 가능하다.
viewDidLoad() {
super.viewDidLoad()
async {
let users = await fetchUsers()
self.users = users
DispatchQueue.main.async {
self.tableView.reload()
}
}
이러한 코드에서 사실 큰 차이가 없어보이지만
위의 비동기 처리가 되는 코드가 중첩적으로, 콜되면 엄청난 차이를 보인다.
예를들어 다음과 같은 코드가 아름답게 변화할수있다.
viewDidLoad() {
super.viewDidLoad()
fetchUsers() { users in
getOtherUsers(from: users) { others in
anotherUsers(from: others) { another in
...
}
}
}
}
이러한 코드가 async await을 사용하면
viewDidLoad() {
super.viewDidLoad()
async {
let users = await fetchUsers(from: url)
let otherUsers = await getOtherUsers(from: users)
let anotherUsers = await anotherUsers(from: otherUsers)
self.users = anotherUsers
DispatchQueue.main.async {
self.tableView.reload()
}
}
또한 여기에서 Result type을 이용해서 에러핸들링을 해줄수 있다.
enum MyError: Error {
case failToGet
}
private func fetchUsers() async -> Result<[Users], Error> {
guard let url = url else {
.failure(MyError.failToGet)
}
do {
let (data, _) = try await UrlSession.shared.data(from: url)
let user = try JSONDecoder().decode([User].self, from: data)
return .success(user)
}
catch {
return .failure(error)
}
}
viewDidLoad() {
super.viewDidLoad()
async {
let result = await fetchUsers()
switch result {
case .success(let users):
self.users = users
DispatchQueue.main.async {
self.tableView.reload()
}
case .failure(let error):
print(error.localizationDescription)
}
}
}
이러한 화려한 아주 깔끔한 코드를 짤수 있도록 도와주는것이 async await이다.
Uploaded by N2T