Swift에서 Conceurrency(async, await)와 전통적인 Closure 두 가지를 대응하는 방법을 실시하다

14572 단어 iOSSwiftTwittertech
https://github.com/mironal/TwitterAPIKit 요청을 진행하는 여러 방법으로Concurrency(async,await) 형식과Closure 형식의 응답 결과를 얻을 수 있습니다.
아무것도 고려하지 않고 설치하면 코드의 양이 늘어나 번거로울 수 있기 때문에 간단하게 보기 위해 어떻게 설치했는지 설명하고 싶습니다.
먼저 Conceurrency 코드와 Closure 코드의 차이점을 설명합니다.
Swift의 Conceurrency는 다음 코드입니다.
class HogeClass {
    func asyncFunction() async -> Int {
        return 0
    }
}

let hoge = HogeClass()
let value = await hoge.asyncFunction()
전통Closure의 코드를 사용했다면 다음과 같은 코드일 것 같다(이것은 모두가 본 사람이다).
class HogeClass {
    func asyncFunction(_ block: (Int) -> Void) async -> Int {
        block(0)
    }
}

let hoge = HogeClass()
hoge.asyncFunction { hoge in 
}

두 가지 설치


과제.


그렇다면 여기서 Concurrency와 Closure 두 가지가 대응하는 상황에서 어떻게 하면 좋을까요?
간단하게 생각하면 아래와 같이 하나하나 실시할 수 있을 것 같습니다.
class HogeClass {
     func asyncFunction() async -> Int {
        return 0
    }
    func asyncFunction(_ block: (Int) -> Void) async -> Int {
        block(0)
    }
}
이 경우 방법의 수량이 증가할수록 설치가 번거롭다.
100가지 방법이 있으면 각각 Conceurrency와 Closure를 설치해 200개의 API를 실현해야 한다.그리고 조금 다른 코드를 많이 써야 해서 지루해요.

해결책


많이 찾아봤는데https://github.com/Alamofire/Alamofire 대응하는 느낌이 좋아서 참고했어요.
이 문제는 실제 값이 저장된 용기를 되돌려주고 그 컨테이너는 컨테이너와 Closure에 대응해서 해결할 수 있다.
여기서 말한 컨테이너는 ResultOption처럼 실제 값을 저장하는 유형이다.
세부적인 부분은 생략했지만 다음과 같이 실시할 수 있다.
// 例えば以下のようなコードをコンテナとして実装
struct AsyncResult<T> {
   // Concurrency 対応
   var result: T {
	get async {
	    return await withCheckedContinuation { c in
	            result { value in
		        c.resume(returning: value)
	            }
	    }
	}
   }
   // Closure 対応
   func result(_ block: (T) -> Void) {
       // ここは工夫して実装する必要があります
       block(0)
   }
}

// 先の HogeClass は以下のように実装できます。
// メソッドの実装は一つですみます。
class HogeClass {
    func asyncFunction() -> AsyncResult<Int> {
	return AsyncResult()
    }
}

// 使用するときは以下のように Concurrent 方式でも Closure 方式でも結果を取得できます。

let hoge = HogeClass()

let value = await hoge.asyncFunction().result

hoge.asyncFunction.result { value in }
이로써 100가지 방법이 있어도 100개만 설치하면 된다.
실제로AsyncResult 주변 코드를 써야 하기 때문에 110개 정도의 설치량인가요?

추가 정보


이 방법의 또 다른 장점은 콘서트를 extension으로 표현할 수 있다는 것이다.
컨투어링에 실제로 해당되는 경우
  • #if compiler(>=5.5.2) && canImport(_Concurrency)
  • @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  • 추가 등 코드가 필요하기 때문에 번잡할 수 있기 때문에 extension으로 나누면 간단합니다.
    // AsyncResult.swift
    struct AsyncResult<T> {
       // Closure 対応
       func result(_ block: (T) -> Void) {
           block(0)
       }
    }
    
    // AsyncResult+Concurrency.swift
    
    #if compiler(>=5.5.2) && canImport(_Concurrency)
    
    @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
    extension AsyncResult {
        var result: T {
    	get async {
    	    return await withCheckedContinuation { c in
    	            result { value in
    		        c.resume(returning: value)
    	            }
    	    }
    	}
       }
    }
    #endif
    

    더욱 상세한 실시 예


    실제 코드 예 몇 개를 미리 붙이다.
    https://github.com/mironal/TwitterAPIKit/blob/main/Sources/TwitterAPIKit/Extensions/Concurrency.swift
    https://github.com/mironal/TwitterAPIKit/blob/main/Sources/TwitterAPIKit/SessionTask/TwitterAPISessionDelegatedJSONTask.swift

    총결산


    컨투어링 방식에서도 클로저 방식과 양자에 대응하는 방법의 제작 방법을 소개했다.
    그러나 이 방법은 반환값을 저장하는 용기의 코드를 써야 하는 경우도 있었다.
    따라서 似たコードを2回書く手間 と コンテナのコードを書く手間의 원가를 꼼꼼히 비교해야 한다고 생각합니다.
    제가 만든 TwitterAPIKit도 처음에는 컨셉트 방식으로 클로저 방식의 쌍방을 쓰려고 했지만 트위터 API가 200개 정도 되는 게 귀찮아서 이번에 소개한 방법을 사용했습니다.
    앞으로 일정 기간은 스위프트 컨투어링의 과도기가 될 수 있으니 클로저 형식과 섞을 필요가 있는데 참고가 된다면 좋겠다.

    좋은 웹페이지 즐겨찾기