꿈돌이랜드

[Swift] Result 타입 본문

Programming/Swift

[Swift] Result 타입

loinsir 2023. 10. 20. 15:06
반응형

Result

  • 연관 값을 포함한 success 또는 failure를 나타낼 수 있는 타입
  • 제네릭 enum 타입으로 선언되어있다. Failure는 반드시 Error 프로토콜을 채택한 타입이어야 합니다.
    @frozen
    enum Result<Success, Failure> where Failure : Error
  • 어떤 동작의 수행결과(대표적으로 네트워킹)를 success인지 failure인지 구분해서 나타낼 수 있습니다.
  • case로 success와 result를 가지고, 각 case의 연관값으로 제네릭타입의 넣어준 값을 저장합니다.

Result의 쓰임 예시는 아래 아티클을 참조해주세요

Writing Failable Asynchronous APIs

오류를 동기식으로 반환하지 못할 때, API의 일부로 Result를 반환하는 것을 제안합니다.

→ API의 실행 리턴 결과를 Result 타입으로 내보내보자.

Overview

  • 함수와, 메서드, 다른 API를 작성할 때, API의 사용은 실패할 수 있습니다.
  • throws 키워드를 사용해서 해당 API 호출이 에러를 throw 할 수 있을 것이라 작성할 수 있습니다.
  • 하지만, throws 키워드는 비동기 호출에서는 사용할 수 없죠. 대신에 Result enum값을 사용해서 비동기 호출의 성공과 실패를 캡처할 수 있습니다.
  • 그리고 success와 failure case각각의 연관값으로 호출로 발생한 정보를 가져올 수 있습니다.
  • 아래 비동기적으로 랜덤 숫자를 가져오는 예시입니다.
    • 메서드는 void를 동기적으로 리턴하지만, 비동기적으로 completionHandler의 Result 인스턴스를 통해 random 결과를 가져오거나 실패 정보를 가져올 수 있습니다.
    let queue = DispatchQueue(label: "com.example.queue")
    
    
    enum EntropyError: Error {
        case entropyDepleted
    }
    
    
    struct AsyncRandomGenerator {
        static let entropyLimit = 5
        var count = 0
    
    
        mutating func fetchRemoteRandomNumber(
            completion: @escaping (Result<Int, EntropyError>) -> Void
        ) {
            let result: Result<Int, EntropyError>
            if count < AsyncRandomGenerator.entropyLimit {
                // Produce numbers until reaching the entropy limit.
                result = .success(Int.random(in: 1...100))
            } else {
                // Supply a failure reason when the caller hits the limit.
                result = .failure(.entropyDepleted)
            }
    
    
            count += 1
    
    
            // Delay to simulate an asynchronous source of entropy.
            queue.asyncAfter(deadline: .now() + 2) {
                completion(result)
            }
        }
    }
  • 이 랜덤 숫자 제너레이터의 사용자는 success와 failure 케이스 각각을 어떻게 핸들링 할지를 정해주면 됩니다.
    var generator = AsyncRandomGenerator()
    
    
    // Request one more number than the limit to trigger a failure.
    (0..<AsyncRandomGenerator.entropyLimit + 1).forEach { _ in
        generator.fetchRemoteRandomNumber { result in
            switch result {
            case .success(let number):
                print(number)
            case .failure(let error):
                print("Source of randomness failed: \(error)")
            }
        }
    }
    
    
    print("Waiting on some numbers.")
    
    
    dispatchMain()
    /* Prints:
    success(29)
    success(46)
    success(85)
    success(39)
    success(84)
    Source of randomness failed: entropyDepleted
    */


Uploaded by N2T

반응형