ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Swift Concurrency - 이전 버전에서 비동기 시스템 API 사용하기
    Concurrency 2023. 3. 16. 13:54

    안녕하세요. 그린입니다🍏

    이번 포스팅에서는 비동기 시스템 API를 이전 버전에서 사용할 수 있도록 구현하는 학습을 해보겠습니다🙌

     

    Swift Concurrency가 iOS 13부터 사용이 가능하게 나왔어도 계속 디벨롭을 거쳐 왔습니다. (당연하지만!?)

    그렇기에 오늘 예시로 들어볼 iOS 15 이상에서 URLSession 네트워킹에서 편하게 async/await를 사용할 수 있지만 그 하위 버전인 iOS 13, 14대에서는 직접 사용하지 못하는 불편함이 있었어요😭

    이전 포스팅에서도 잠깐 나왔는데 Swift 5.5 부터 비로소 기존 코드에서도 비동기 처리를 할 수 있게 변화했다고 했죠?

    즉 Xcode 13.2부터 호환이 되지만 그 기준이 OS로는 iOS 15, macOS Monterey입니다.

     

    그래서 오늘 iOS 15 미만에서도 비동기 시스템 API를 사용할 수 있도록 이전 버전 대응을 해볼께요🎉

     

    iOS 15 미만에서 비동기로 URLSession 네트워킹 하기

    자 우선 iOS 15 이상에서는 아래와 같이 session의 data 통신을 비동기로 할 수 있습니다.

    struct ModelLoader<Model: Decodable> {
        var session = URLSession.shared
        var decoder = JSONDecoder()
    
        func loadModel(from url: URL) async throws -> Model {
            let (data, _) = try await session.data(from: url)
            let model = try decoder.decode(Model.self, from: data)
            return model
        }
    }

    그렇지만, 만약 iOS 15 미만에서 동일하게 사용한다면 아래와 같은 에러 문구를 만날 수 있습니다.

    // Error: 'data(from:delegate:)' is only available in iOS 15.0 or newer

    즉, iOS 15에서 data(from:delegate:) 메서드가 비동기로 처리되도록 하는것이 생겼다고 볼 수 있죠.

     

    그렇지만, 우리의 미니멈 타겟은 15 이상이 아닐 경우가 많으니 대응을 해봐야겠습니다!

    기존 프로젝트 코드에서 URLSession 네트워킹에 async,await인 Swift Concurrency를 붙이고 싶다입니다🥸

     

    자 그럼 우선 URLSession을 확장하여 구현해볼께요.

    @available(iOS, deprecated: 15.0, message: "Use the built-in API instead")
    extension URLSession {
        func data(from url: URL) async throws -> (Data, URLResponse) {
            try await withCheckedThrowingContinuation { continuation in
                let task = self.dataTask(with: url) { data, response, error in
                    guard let data = data, 
                    let response = response else {
                        let error = error ?? URLError(.badServerResponse)
                        return continuation.resume(throwing: error)
                    }
    
                    continuation.resume(returning: (data, response))
                }
    
                task.resume()
            }
        }
    }

    먼저 iOS 15 미만에서만 사용하고 이상에서 사용 시 디프리케이트 되었다는걸 안내해주도록 하죠!

    이유는 동일한 data 메서드인데 iOS 15이상에서 사용 시 기본 제공해주는걸 사용할 수 있도록 배려하기 위함입니다.

    보시면 data 메서드를 async하게 만들어 비동기 호출임을 명시해줍니다.

    withCheckedThrowingContinuation으로 만들어요.

    이전에 다뤄봤던 continuation 개념이라고 생각하면 쉽습니다🙋🏻

     

    내부에서 실제로 통신 중 에러가 나지 않고 정상적인 data가 들어온다면 continuation의 resume으로 반환해줍니다.

     

    이게 다에요!!!

    이걸 다뤄보면서 핵심은 URLSession뿐 아니라 하위 버전에서 아직 제공하지 않는 비동기 시스템 API를 이런식으로 확장하여 만들고 사용할 수 있습니다.

    물론 Swift Concurrency 자체가 iOS 13 이상에서 제공되기에 그 미만 버전의 지원은 불가합니다🥊

     

    마무리

    실제로 이런 구현을 통해 많이 사용할지는 아직 다뤄보지 못했지만 충분히 기존 프로젝트 코드에서 호환할 수 있게 사용할 수 있을것 같습니다.

     

    [참고 자료]

    https://www.swiftbysundell.com/articles/making-async-system-apis-backward-compatible/

     

    Making async system APIs backward compatible | Swift by Sundell

    Although Swift 5.5’s new concurrency system is becoming backward compatible in Xcode 13.2, some of the built-in system APIs that make use of these new concurrency features are still only available on iOS 15, macOS Monterey, and the rest of Apple’s 2021

    www.swiftbysundell.com

Designed by Tistory.