Meet async/await in Swift
async/await 알아보기
Introduction
비동기 프로그래밍은 많은 사람들에게 일상적인 활동이다. 하지만 장황하고, 복잡하고 부정확하게 사용함 async/await는 그걸 도와줌
Body
SDK에는 awaitable한 메소드가 많이 있음 예를들어, UIImage
동기 - preparingThumbnail 동기 함수는 함수가 끝나기를 기다리는 동안 thread를 막음 → 즉, 끝날때까지 thread는 아무것도 할수 없음
비동기 - prepareThumbnail 비동기 함수는 함수가 실행하는동안 thread는 자유 → 즉, 실행하는동안 thread는 다른 작업을 할수있음 작업이 끝나면 completionHandler로 call 함 비동기 작업이 끝나면 알려주는 방법은 completionHandler, delegate call backs가 있음
Ex) 아이템 리스트가 있고 각 행에 사진의 썸네일을 보여줌(서버에 저장된)
String을 UIImage로 변경하는 방법은 일련의 단계를 거침 1.thumbnailURLRequest로 String → URLRequest 2.URLSession’s dataTask로 request → data 3.UIImage로 data → UIImage 4.prepareThumbnail로 원본 이미지를 썸네일로 render → 몇 개의 operations은 이전 작업 결과에 의존함, 그래서 순서가 있음
작업들 중 thumbnailURLRequest와 UIImage 값을 빠르게 반환 그래서 동기작업으로 해도됨 하지만 dataTask와 prepareThumbnail 작업은 시간이 많이 소요 → 즉, 순서대로 진행해도 시간이 걸리는 작업이 있기 때문에 비동기 함수를 사용해야함
예를들어, completionHandler
fetchThumbnail함수 아규먼트는 String, completionHandler completionHandler는 output을 호출자에게 반환
fetchThumbnail함수가 먼저 실행 그 후, thumbnailURLRequest함수 실행 동기함수여서 completionHandler 없음 동기 → 다른 작업 막음
URLSession’s dataTask 함수는 비동기여서 completionHandler가 있음 비동기 → 실행되는동안 다른 작업을 할 수 있음 dataTask 작업 시작하려면 resume() 시작
완료되면 completionHandler가 data, response, error를 처리함
error처리
image data 처리 → 동기
이미지가 생성되면 썸네일 로드 → completion(thumbnail, nil) 성공하면 thumbnail, 실패하면 nil
작업이 진행되는동안 thread는 다른 작업 수행 가능
여기 코드에는 문제가 있음
guard else return 구문때문에 completion쓰는 걸 잊음 → FetchThumbnail의 호출자는 FetchThumbnail이 작업을 완료하면 실패하더라도 알림을 받음 → 데이터에서 UIImage를 만들거나 Thumbnail 준비하는 데 실패하면 fetchThumbnail의 호출자에게 알림이 표시되지 않고 행이 업데이트 안됨, spinner만 계속 돌아감
누락된 부분 추가해줌 Swift는 함수를 통해 실행이 어떻게 진행되든 값이 반환되지 않으면 오류가 발생 하지만 여기서는 Swift’s usual error handling mechanism 을 사용할 수 없음 → Swift가 우리의 작업을 확인할 수 없다는 뜻 → 컴파일때 에러 확인을 못하고, 런타임때 에러를 확인 fetchThumbnails는 클로져이기 때문에 항상 호출되는지 확인하고 싶지만 Swift에서는 강제로 호출할 수 있는 방법이 없음 그래서 guard else return에서 error 확인을 못함 → 쨋든 2개 동기, 2개 비동기를 순차적으로 진행하게 만들었으나 올바르게쓰기 어렵고, 의미모호하고, 따라하기 어려움
→ 안전한 방법인 Result 타입을 넣어서 수정 하지만 코드가 못생기고 길어짐
Async/Await로 해보기
아규먼트는 String
async 키워드
thtrows 에러처리
return는 UIImage 로 간단!
thumbnailURLResquest는 동기함수
URLSettion.shard.data는 datatask와 같음 Foundation에서 제공하고 비동기임 다른점은 datatask awaitable함 throws때문에 try작성, async때문에 await 작성 error가 발생하면 fetchThumbnail에서 에러를 던짐
UIImage(data:) 는 동기 thumbnail 실행 중 error면 throw
-> 직선코드 -> 항상 에러처리 가능 → 안전함
함수가 아니여도 비동기임 → await 키워드 필요 프로퍼티, 이니셜라이즈도 비동기면 await 작성
thumbnail 프로퍼티는 sdk아니라 작성한거 get에 async를 작성 비동기는 get only만 가능 → set 불가능
for문에도 await 가능
await 키워드는 비동기 함수가 일시 중단 될 수 있다는 것을 나타냄
비동기 함수가 일시 중단된다는 것은 무엇을 의미하는지?
함수가 실행 중인 스레드를 해당 함수로 직접 제어
thumbnailURLRequest와 같은 일반적인 함수(동기함수)는 스레드가 완료될 때까지 작업을 수행할 때 까지 완전히 점유함
함수가 끝나면 값을 리턴하거나 에러를 던짐
다시 제어 권한을 돌려줌 → 일반적인 함수가 스레드 제어를 포기하는 유일한 방법
async function는 스레드 제어를 포기할 수 있음 → 일시중단함
일반함수와 동일하게 함수를 호출하면 스레드 제어 가능
실행되면 비동기 기능을 일시 중단될 수 있음 → 스레드 제어 포기
함수에 스레드 제어를 주는게 아니라 스레드에 대한 제어권을 시스템에 제공
그러면 함수도 일시 중단함
일시 중단이란 "당신이 해야 할 일이 많다는 것을 알고 있습니다. 무엇이 가장 중요한지는 당신이 결정합니다.”를 의미
기능이 일시 중단되면 시스템은 스레드를 사용하여 다른 작업을 수행할 수 있음
어느 시점에서 시스템은 가장 중요한 작업이 이전에 일시 중단되었던 비동기 함수를 계속 실행하는 것이라고 결정함 → 이 시점에 시스템은 비동기 함수를 다시 시작함(resume)
그럼 비동기 함수는 다시 스레드를 제어하고 작업할 수 있음 또한 원한다면 스스로 중단도 가능, 필요한 만큼 스스로 중단 가능
async 키워드가 있다고(비동기라고) 무조건 일시중단 하는 건 아님 await 라고 함수가 거기서 일시중단 하는 것도 아님
fetchThumbnail 함수로 일시중단 시 어떤 일이 일어나는지 다시 확인
fetchThumbnail이 URLsession의 비동기 데이터 메서드를 호출하면 데이터 메서드는 일시 중단을 통해 비동기 함수만 수행할 수 있는 특수한 방법으로 스레드에서 실행을 중지
스레드 제어를 시스템에 제공, URLSession data method에 작업을 예약하도록 시스템에 요청
그러나 이 시점에서는 시스템이 제어 상태이므로 작업이 즉시 시작되지 않을 수 있음 만약 fetchThumbnail이 호출된 후 사용자가 버튼을 눌러 일부 데이터를 업로드한다고 한다면 (ex 게시물에 대한 반응) 시스템은 이전에 대기 중인 작업을 하기전에 사용자의 응답을 게시하는 작업을 자유롭게 실행할 수 있음
작업이 완료되면 URLSession data method를 다시 시작하거나 시스템이 다른 작업을 대신 실행할 수 있음
URLSession data method가 끝나면 다시 fetchThumbnail로 돌아감
Conclusion
Swift가 비동기 호출을 await 키워드로 표시해야 한다고 주장하는 이유는?
→ 기능이 일시 중단된 상태에서 다른 작업을 수행할 수 있고 즉, 기능이 일시 중단 되면 앱 상태가 크게 변경될 수 있다는 점때문 completion handlers 마찬가지임
그러나 async/await은 모든 형식과 들여쓰기가 없기 때문에 await키워드는 코드 블록이 하나의 트랜잭션으로 실행되지 않음을 인식하는 방법
async/await에 기억해야할 중요한 사항
함수를 async으로 표시하면 일시 중단이 허용 함수가 자체적으로 일시 중단되면 호출자도 일시 중단 → 호출자도 비동기
비동기 함수에서 한 번 또는 여러 번 일시 중단할 수 있는 위치를 가리키기 위해 await 키워드를 사용
비동기 기능이 일시 중단되는 동안 스레드는 차단되지 않음 시스템은 다른 작업을 자유롭게 예약할 수 있고 나중에 시작되는 일도 먼저 실행할 수 있음 → 즉, 일시 중단되는 동안 앱의 상태가 크게 변경될 수 있음을 의미
비동기 함수가 다시 시작되면 호출한 비동기 함수에서 반환된 결과가 원래 함수로 되돌아 옴, 실행은 중단되었던 바로 그 자리에서 계속됨
Last updated