EEYatHo 앱 깎는 이야기

Swift ) async/await - EEYatHo iOS 본문

iOS, Swift/Swift Theory

Swift ) async/await - EEYatHo iOS

EEYatHo 2023. 1. 16. 14:39
반응형

 

async/await


  • Thread 와 GCD 이후, Swift 5.5 에서 나온 최신식 동시성 지원 API
  • 정확히는 키워드(async)와 피연산자(await)
  • 코루틴 모델을 도입 ( 실행을 일시정지 할 수 있는 함수 )
  • async/await-propasal 링크

 

 

 

탄생 배경


  • 들여쓰기가 가득한 콜백 지옥의 비동기 코드들이 존재할 수 있음
  • 특히나, 분기를 거처서 한쪽에만 비동기 코드가 필요한 경우, 더더욱 들여쓰기와 콜백 지옥이 발생하기 쉬움
  • 콜백은 오류 처리와 함께 사용할 때, 구현부를 장황하게 만듬
  • 콜백 호출이나 return문을 까먹는 경우도 자주 발생
func processImageData(completionBlock: (_ result: Image?, _ error: Error?) -> Void) {
    loadWebResource("dataprofile.txt") { dataResource, error in
        guard let dataResource = dataResource else {
            completionBlock(nil, error)
            return
        }
        loadWebResource("imagedata.dat") { imageResource, error in
            guard let imageResource = imageResource else {
                completionBlock(nil, error)
                return
            }
            decodeImage(dataResource, imageResource) { imageTmp, error in
                guard let imageTmp = imageTmp else {
                    completionBlock(nil, error)
                    return
                }
                dewarpAndCleanupImage(imageTmp) { imageResult, error in
                    guard let imageResult = imageResult else {
                        completionBlock(nil, error)
                        return
                    }
                    completionBlock(imageResult)
                }
            }
        }
    }
}

processImageData { image, error in
    guard let image = image else {
        display("No image today", error)
        return
    }
    display(image)
}
func processImageData2(recipient: Person, completionBlock: (_ result: Image) -> Void) {
    let swizzle: (_ contents: Image) -> Void = {
        // ... continuation closure that calls completionBlock eventually
        let swizzledImage = contents // swizzle logic
        completionBlock(swizzledImage)
    }
    if recipient.hasProfilePicture {
        swizzle(recipient.profilePicture)
    } else {
        decodeImage { image in
            swizzle(image)
        }
    }
}

 

 

 

장점


  • async/await 를 사용하면, 비동기 코드들을 마치 동기 코드처럼 간결하게 바꿔줌
  • 호출부에서 어떤 프로세스를 거치는지 한눈에 알 수 있음
func loadWebResource(_ path: String) async throws -> Resource
func decodeImage(_ r1: Resource, _ r2: Resource) async throws -> Image
func dewarpAndCleanupImage(_ i : Image) async throws -> Image

func processImageData() async throws -> Image {
  let dataResource  = try await loadWebResource("dataprofile.txt")
  let imageResource = try await loadWebResource("imagedata.dat")
  let imageTmp      = try await decodeImage(dataResource, imageResource)
  let imageResult   = try await dewarpAndCleanupImage(imageTmp)
  return imageResult
}
func processImageData2(recipient: Person) async -> UIImage {
    var image = recipient.profilePicture
    if recipient.hasProfilePicture {
        image = await decodeImage()
    }

    let swizzledImage = image // swizzle logic
    return swizzledImage
}

 

 

 

Task


  • 동기함수에서 async 함수 호출하기
func syncFunc() {
    Task {
        let image = await decodeImage()
    }
}

 

 

 

async let 


  • async 함수를 호출할 때 무조건 await 를 사용하면, 하나씩 호출하고 기다리는, 직렬적으로 작동
  • 여러개의 async 함수를 병렬적으로 호출하고 모두 끝나면 다음 작업을 하고 싶을 때 async let 을 사용
func asyncFunc1() async -> UIImage {
    sleep(1)
    return UIImage()
}
func asyncFunc2() async -> UIImage {
    sleep(2)
    return UIImage()
}
func asyncFunc3() async -> UIImage {
    sleep(3)
    return UIImage()
}

func images() async throws -> [UIImage] {
    async let image1 = asyncFunc1()
    async let image2 = asyncFunc2()
    async let image3 = asyncFunc3()

    let images = await [image1, image2, image3]
    return images
}

 

 

 

MainActor


  • async/await 가 적용된 메인쓰레드 접근용 API
  • DispatchQueue.main 에는 await 사용시, async 함수가 아니라고 나옴
Task {
    do {
        movies = try await getMovie()
        await MainActor.run {
            movieCollectionView.reloadData()
        }
    } catch {
        // error handling.
    }
}

 

 

 

Reference


 

GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Lang

This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhance...

github.com

 

 

Concurrency — The Swift Programming Language (Swift 5.7)

Concurrency Swift has built-in support for writing asynchronous and parallel code in a structured way. Asynchronous code can be suspended and resumed later, although only one piece of the program executes at a time. Suspending and resuming code in your pro

docs.swift.org

 

Comments