Swift 5.5์์ ์๊ฐ๋ Async/Await์ ๋ํด ๊ณต๋ถํด๋ณธ๋ค.
๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ์ด์
thumbnail์ fetchํ๋ method๊ฐ ์๋ค๊ณ ํ์.
- thumbnailURLRequest: ๋ฐ๋ String์ ๋ฐํ์ผ๋ก URL Request ๊ฐ์ฒด๋ฅผ ๋ง๋ฆ
- dataTask: request๋ฅผ ๋ฐํ์ผ๋ก ๋คํธ์ํฌ ์์ฒญ
- UIImage(data): ๋ฐ์ ์์ฒญ์ ๋ฐํ์ผ๋ก imageํ
- prepareThumbnail: ํ๋ฉด์ ๋ณด์ฌ์ง๊ธฐ ์ image ์ฒ๋ฆฌ
์์ 4๋จ๊ณ์ค 2๋จ๊ณ์ธ ๋คํธ์ํฌ ์์ฒญ์ ๊ฒฝ์ฐ ๋ค๋ฅธ ์์ ์ ๋นํด ์๋นํ ์ง์ฐ์ด ๋ง๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ํด๋น ์์ ์ ๋ค๋ฅธ thread์์ ๋๋ฆฌ์ง ์์ผ๋ฉด, ํ์ฌ ์์ ์ด ์งํ๋๊ณ ์๋ thread๊ฐ block ๋๋ค. ์ด๋ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ์ํฅ์ ์ฃผ๊ณ , ๋ฆฌ์์ค๋ฅผ ๋ญ๋นํ๋ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์จ๋ค.
Completion Handler
์ด๋ฐ ์ํฉ์์ concurrent programming์ ํ๊ธฐ ์ํด์ ์ฐ๋ฆฌ๋ completion handler๋ฅผ ์ฌ์ฉํด์๋ค.
func fetchThumbnail(for id: String, completion: @escaping (UIImage?, Error?) -> Void) {
let request = thumbnailURLRequest(for: id)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(nil, error) // ๐
} else if (response as? HTTPURLResponse)?.statusCode != 200 {
completion(nil, FetchError.badID) // ๐
} else {
guard let image = UIImage(data: data!) else {
return // ๐ ??? ๋๋ฝ (1)
}
image.prepareThumbnail(of: CGSize(width: 40, height: 40)) { thumbnail in
guard let thumbnail = thumbnail else {
return // ๐ ??? ๋๋ฝ (2)
}
completion(thumbnail, nil) // ๐
}
}
}
task.resume()
}
์ ๋ ๊ฒ ๊ฐ์ง๋ง, ๋ฌธ์ ๊ฐ ์๊ฒผ๋ค. image ๋ณํ์ด ๋์ง ์์๊ฑฐ๋(1), thumbnail์ ๋ณํ์ด ์ ์ด๋ฃจ์ด์ง์ง ์์ ๊ฒฝ์ฐ(2)์ completion handler์ nil
์ ์ ๋ฌํ์ด์ผ ํ๋๋ฐ, ์๋ฌด๋ฐ ์ฒ๋ฆฌ๋ฅผ ํ์ง ์์๋ค. ์ด๋ด ๊ฒฝ์ฐ, ํด๋น ํจ์๋ฅผ ํธ์ถํ๋ ์ชฝ์์๋ image๊ฐ ๋ณด์ด์ง ์์ spinner๊ฐ ๊ณ์ํด์ ๋์๊ฐ๊ณ ์๋ ์ํ์ผ ๊ฒ์ด๋ค.
func fetchThumbnail(for id: String, completion: @escaping (UIImage?, Error?) -> Void) {
let request = thumbnailURLRequest(for: id)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(nil, error) // ๐
} else if (response as? HTTPURLResponse)?.statusCode != 200 {
completion(nil, FetchError.badID) // ๐
} else {
guard let image = UIImage(data: data!) else {
completion(nil, FetchError.badImage) // ๐
return
}
image.prepareThumbnail(of: CGSize(width: 40, height: 40)) { thumbnail in
guard let thumbnail = thumbnail else {
completion(nil, FetchError.badImage) // ๐
return
}
completion(thumbnail, nil) // ๐
}
}
}
task.resume()
}
๋น์ฅ์ ์์ ๊ฐ์ด ํด๊ฒฐํ ์ ์๋ค. ํ์ง๋ง ๋ฌธ์ ๋ completion handler์ ํธ์ถ์ด, ์ ์ ์ผ๋ก ๊ฐ๋ฐ์์ ์ฑ ์์ด๋ผ๋ ๊ฒ์ด๋ค. ์ปดํ์ผ๋ฌ๊ฐ ํด์ค ์๊ฐ ์๋ค. ํธ์ถํ์ง ์๊ฒ๋๋ฉด ์ด๋์ ์์ฑ์ ๊น๋จน์๋์ง ํ์ ํ๊ธฐ ์ด๋ ค์ ๋๋ฒ๊น ๋ ์ด๋ ค์์ง๋ค.
Result Type
func fetchThumbnail(for id: String, completion: @escaping (Result<UIImage, Error>) -> Void) {
let request = thumbnailURLRequest(for: id)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(.failure(error)) // โ
} else if (response as? HTTPURLResponse)?.statusCode != 200 {
completion(.failure(FetchError.badID)) // โ
} else {
guard let image = UIImage(data: data!) else {
completion(.failure(FetchError.badImage)) // โ
return
}
image.prepareThumbnail(of: CGSize(width: 40, height: 40)) { thumbnail in
guard let thumbnail = thumbnail else {
completion(.failure(FetchError.badImage)) // โ
return
}
completion(.success(thumbnail)) // โ
}
}
}
task.resume()
}
์์ ์ฝ๋๋ณด๋ค ์ฝ๊ฐ ๋ ์์ ํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์๊ธด ํ๋ค. Result
Type์ ํ์ฉํ๋ ๊ฒ์ด๋ค. ํ์ง๋ง ๋ ๋ชป์๊ฒจ์ง๊ณ ๊ธธ์ด์ ธ๋ฒ๋ ธ๋ค. Future
์ ๊ฐ์ ๋ฐฉ์์ ํตํด ๋น๋๊ธฐ ์ฝ๋๋ฅผ ๊ฐ์ ํ๋ ค๋ ๋
ธ๋ ฅ๋ค๋ ์์๋ค. ํ์ง๋ง ์ฌ์ ํ ์ฝ๊ณ , ๊ฐ๋จํ๋ฉฐ, ์์ ํ ์ฝ๋๋ฅผ ๋ง๋ค์ง๋ ๋ชปํ๋ค.
Async/Await
func fetchThumbnail(for id: String) โ
async โ
throws -> UIImage {
let request = thumbanilURLRequest(for: id)
let (data, response) = โ
try โ
await URLSession.shared.data(for: request)
guard (response as? HTTPURLResponse)?.statusCode == 200 else {
throw FetchError.badID
}
let maybeImage = UIImage(data: data)
guard let thumbnail = โ
await maybeImage?.thumbnail else {
throw FetchError.badIamge
}
return thumbnail
}
async
: ๋น๋๊ธฐ๋ก ๋ก์ง์ด ์ฒ๋ฆฌ๋ ๊ฑฐ์ผthrows
: ์คํจํ๋ฉด ์๋ฌ๋ฅผ ๋์ง ๊ฑฐ์ผtry
: dataMethod๊ฐ ์๋ฌ๋ฅผ ๋์ง๋ ํจ์๋ผ ๋ฐ์์ค์ผ ํ๋ค.await
: ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌ๋๊ณ , ๊ฒฐ๊ณผ๊ฐ์ด ์ฌ ๋๊น์ง ์์ ์งํ์ฌํญ์ ๋ฉ์ถฐ์ค- ํด๋น ๋จ๊ณ์์ ์์ thread๋ suspend๋๋ ๊ฒ์ด ์๋๊ณ , ์์ ๋กญ๊ฒ ๋ค๋ฅธ ์์ ์ ์ฒ๋ฆฌํ ์ ์๋ค.
- Property๋
async
ํ ์ ์๋ค. ๊ทธ ๊ฒฐ๊ณผ ์ฌ์ฉํ๋ ์ชฝ์์await
ํค์๋๋ฅผ ์ถ๊ฐํ๋ค.- initializer๋
async
ํ ์ ์๋ค.
- initializer๋
20์ค ์ง๋ฆฌ ์ฝ๋๊ฐ 5์ค๋ก ์ค์๋ค. ์ฝ๋๋ ์์ฐจ์ ์ผ๋ก ์ฝํ๋ค.
Property Async
์์์ 5๋ฒ ํญ๋ชฉ์์ Property๋ async
ํ ์ ์๋ค ํ๋๋ฐ, ์ด๋ป๊ฒ ๊ตฌํ๋๋์ง ์ดํด๋ณด์.
extension UIImage {
var thumbnail: UIImage? {
get โ
async {
let size = CGSize(width: 40, height: 40)
return โ
await self.byPreparingThumbnail(ofSize: size)
}
}
}
์ค์ง ์ฝ๊ธฐ ์ ์ฉ Property๋ง์ด
async
ํค์๋๋ฅผ ๋ฌ ์ ์๋ค.
Async Sequences
initializer, property, function ์ด์ธ์๋ async
ํค์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ๋ฐ๋ก for loop์ด๋ค.
for await id in staticImageIDsURL.lines {
let thumbnail = await fetchThumbnail(for: id)
collage.add(thumbnail)
}
let result = await collage.draw()
์ด ๋ถ๋ถ์ ๋ค์ ๊ธ์์ ๋ค๋ฃจ๋๋ก ํ๊ฒ ๋ค.
Sync & Async
await
ํค์๋๋ก ๋ ํจ์๋ฅผ ์คํ์ํค๋ฉด, ์ง๊ธ๊น์ง ์์
ํ๊ณ ์๋ ์ ์ด๊ถ์ system์ผ๋ก ๋์ด๊ฐ๋ค. system์์๋ ํ์ฌ ์์
์ํฉ๊น์ง suspend๋ ์น๊ตฌ ๋ง๊ณ , ๋ ์ค์ํ ๋
์์ ๋๊ฒจ๋ฐ์ ์ ์ด๊ถ์ผ๋ก ์ฒ๋ฆฌํ๋ค.
system์ผ๋ก code block์ด ๋์ด๊ฐ์ ๋, ๋ฐ๋ก ์คํ๋์ง ์์ ์ ์๋ค. ๋จผ์ ์์ฌ์๋ ์์
์ ์ฒ๋ฆฌํ ํ์์ผ ์คํ๋๋ค. completion handler์ ๋์๊ณผ ๊ฐ๋ค. ํ์ง๋ง ์ด ๊ณผ์ ์์ await
ํค์๋๋ฅผ ํตํด ํ์์ ์์ฑ๋ instruction๊น์ง ํ๋์ transaction์ผ๋ก ์คํ๋์ง ์๋๋ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. await
ํค์๋๋ฅผ ํ์ธํ๋ ์๊ฐ, ํด๋น ์์
ํ๋ฆ์ด suspend๋ ์ ์๊ณ , ๊ทธ ์ฌ์ด์ ๋ค๋ฅธ ์์
๋ค์ ์ฒ๋ฆฌํ๊ฒ ๊ตฌ๋~ ํ๊ณ ์ธ์งํ ์ ์๋ค.
Summary
async
keyword๋ ํจ์๋ฅผ suspend ํ๋๋ก ํ๋ค.await
keyword๋ async function์ด ์คํ์ suspendํ ์ ์์์ ํ์ํ๋ค.- suspend๋๋ ๋์ ๋ค๋ฅธ ์์ ์ด ์คํ๋ ์ ์๋ค.
- ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ async function์ด ์๋ฃ๋๋ฉด
await
์ดํ ๊ณผ์ ์ด ์คํ๋๋ค.
Bridging from sync to async
async
ํจ์๋ฅผ call ํ๊ฒ ๋๋ฉด, callํ๋ ์ชฝ์์ ์์ ๊ฐ์ ์๋ฌ๊ฐ ๋ฌ๋ค. async ํจ์์ ๊ฒฝ์ฐ์๋ ์์ ํธ์ถ ํจ์๋ async
ํค์๋๋ฅผ ๋ฌ์์ฃผ์ด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ฐ ๊ฒฝ์ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ async Task
function์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Task {
await self.asyncFuntion()
}
}
internal func asyncFuntion() async {
print("asyncFuntion!!")
}
}
์ด๋ ์ฐ๋ฆฌ๊ฐ ์ด์ ์ ์ฌ์ฉํ๋ global dispatch queue์ async
ํจ์์ ๋น์ทํ๊ฒ ๋์ํ๋ค. ํด๋น ์์
์ packageํํ์ฌ ๋ค์ thread์์ ์ฆ์ ์คํํ ์ ์๋๋ก ์์คํ
์ผ๋ก ์ ์กํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด, async code๋ฅผ sync context์์ ์คํํ ์ ์๋ค.