티스토리 뷰

반응형

과거에 Continuations 를 이용해서 짰던 코드를 보는데 헷갈렸다.. @)@

리마인드가 필요하군 

 

우선 요 목차(?)가 머릿 속에 있어야한다. 

 

https://developer.apple.com/documentation/swift/checkedcontinuation

 

 

[1] 용어 기억 

가끔 용어도 잘 생각이 안날 때가 있다,, 

 

 

[ Continuation ]

 

비동기 코드를 래핑해서 연속(continuation)을 만든다!  라고 기억하자 

문서에서는 이렇게 표현한다. 

To create a continuation in asynchronous code, 
call the withUnsafeContinuation(function:_:) or withUnsafeThrowingContinuation(function:_:) function. 

 

 

 

[ CheckedContinuation vs  UnsafeContinuation ]

 

잘 까먹는 주요원인이다.

checked / unchecked 이던가..  safe / unsafe 이던가.. 하면 더 쉽게 기억할텐데 따흑,,

 

 

CheckedContinuation 은 resume이 빠졌거나 여러번 불리는 지를 런타임때 체크하고 

UnsafeContinuation 은 체크안한다 (오버헤드를 피하기 위해)

CheckedContinuation performs runtime checks for missing or multiple resume operations. 
UnsafeContinuation avoids enforcing these invariants at runtime because it aims to be a low-overhead mechanism for interfacing Swift tasks with event loops, delegate methods, callbacks, and other non-async scheduling mechanisms

 

이 글에서 자세한 실험을 볼 수 있다. 

 

 

[2] 사용예시

 

보통 두가지 경우에 사용한다. 

 

1) completion -> async/await 

 

completion handler 를 파라미터로 받는 function을  래핑해서 async function 을 만들고 싶을 때 사용한다.

 

여기 예제 잘 설명되어있음 

http://minsone.github.io/swift-concurrency-continuation

 

[Swift 5.7+][Concurrency] Continuations - Closure를 async 코드로 감싸 사용하기

Continuation은 프로그램 상태의 불투명한 표현입니다. 비동기 코드에서 연속(continuation)을 만들려면 withCheckedContinuation(function:_:), withCheckedThrowingContinuation(function:_:) 와 같은 코드를 호출합니다. 비동

minsone.github.io

 

 

2) delegate -> async/await 

 

delegate 패턴 대신 async function 을 만들고 싶을때 사용한다. 

 

예를들어

StoreKit 1 의 대부분은 delegate 패턴인데 

ProductFetcher, ReceiptLoader 등 각각 객체를 만들고 asyn/await 를 사용할 수 있게 해주면 코드가 훨씬 간결해진다.

 

fetchAvailableProducts 을 asyn function으로 만드려면

request 가 성공, 실패할때 불리는 delegate function 내에서 resume이 호출되게 해주면 된다. 

class IAPProductsFetcher: NSObject, SKProductsRequestDelegate {

    private var productsRequest: SKProductsRequest?
    private var productsRequestDoneAction: (([SKProduct]) -> Void)?
    
    private let productIds: [String]

    init(productIds: [String] = IAPProducts.identifiers) {
        self.productIds = productIds
    }
    
    func fetchAvailableProducts() async -> [SKProduct] {
        return await withCheckedContinuation { continuation in
            self.productsRequestDoneAction = {
                continuation.resume(returning: $0)
            }
            self.fetchProducts(matchingIdentifiers: self.productIds)
        }
    }
    
    private func fetchProducts(matchingIdentifiers identifiers: [String]) {
        let productIdentifiers = Set(identifiers)
        
        let productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
        productsRequest.delegate = self
        self.productsRequest = productsRequest
        
        productsRequest.start()
    }
    
    // MARK: - SKProductsRequestDelegate
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        let availableProducts = response.products
        self.productsRequestDoneAction?(availableProducts)
        self.productsRequestDoneAction = nil
    }
    
    func request(_ request: SKRequest, didFailWithError error: Error) {
        self.productsRequestDoneAction?([])
        self.productsRequestDoneAction = nil
    }
}

 

 

 

 

반응형
댓글