# Result 타입 개념

기본적인 에러 처리의 과정은 아래와 같다.

  1. Error 프로토콜 채택 및 에러 정의
  2. throws타입의 함수 정의, 실제 에러 throw
  3. try함수를 통해 에러발생 가능 함수 호출 및 catch로 에러 처리

Result타입은 에러 발생 가능성을 리턴 타입으로 묶어 관리하는 방식이다. throws 타입의 에러 발생 가능 함수는 리턴 타입이 정해져있고 함수에서 에러를 발생시킬 가능성이 있다 뿐이므로 함수 호출시에 반드시 try~catch문으로 에러를 한번 처리해야 한다.

반면 Result타입은 열거형이며 타입 자체적으로 함수의 성공적인 호출 시 반환되는 타입과 에러 발생시 던져지는 에러 타입(열거형)을 갖기 때문에 함수를 Result타입으로 리턴하면 된다. (try ~ catch문을 사용할 필요 없이 switch문으로 분기 가능)

Result 열거형 타입은 <Success, Failure>로 이루어지며, Failure는 Error 프로토콜을 채택한 에러 케이스의 모음집을 갖는것이 일반적이다.

Result타입은 성공 시 success를, 에러 발생 시 failure연관값으로 갖는다. 이들 연관값은 모두 제네릭으로 선언되어 있으므로 아무 타입이나 사용해도 되긴 하다.

// 기존 에러처리 방식
func checkingHeight(height: Int) throws -> Bool {
    if height > 190 {
        throw HeightError.maxHeight
    } else if height < 130 {
        throw HeightError.minHeight
    } else {
        if height >= 160 {
            return true
        } else {
            return false
        }
    }
}

// Result타입 방식
func resultTypeCheckingHeight(height: Int) -> Result<Bool, HeightError> {

    if height > 190 {
        // Result타입의 failure케이스로 반환
        return Result.failure(HeightError.maxHeight)
    } else if height < 130 {
        return Result.failure(HeightError.minHeight)
    } else {
        if height >= 160 {
            // Result타입의 success케이스로 반환
            return Result.success(true)
        } else {
            return Result.success(false)
        }
    }
}

let result = resultTypeCheckingHeight(height: 200)

switch result {
case .success(let data): // switch 바인딩
    print("결과값은 \(data)입니다.")
case .failure(let error):
    print(error)
}

# 네트워크 통신 코드 예시

// 파라미터 타입이 Result로 선언되어 있음
func performRequest2(with urlString: String, completion: @escaping (Result<Data,NetworkError>) -> Void) {

    guard let url = URL(string: urlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if error != nil {
            print(error!)
            // 콜백함수의 파라미터 타입이 Result이므로 열거형 케이스 전달하면 됨
            // NetworkError열거형의 .someError 케이스가
            // failure 케이스의 연관값으로 전달됨
            completion(.failure(.someError))
            return
        }

        guard let safeData = data else {
            // 콜백함수의 파라미터 타입이 Result이므로 열거형 케이스 전달하면 됨
            // NetworkError열거형의 .someError 케이스가
            // failure 케이스의 연관값으로 전달됨
            completion(.failure(.someError))
            return
        }

        // 콜백함수의 파라미터 타입이 Result이므로 열거형 케이스 전달하면 됨
        // 성공 연관값을 전달함
        completion(.success(safeData))

    }.resume()
}

// 클로저 콜백함수의 파라미터가 Result타입 하나로만 전달되고 있다.
performRequest2(with: "주소") { result in
    switch result {
    // someError가 빠져나오게 될 것
    case .failure(let error):
        print(error)
    // safeData가 빠져나오게 될 것
    case .success(let data):
        // 데이터 처리 관련 코드
        break
    }
}

# Reference

  1. 인프런 - 앨런 swift 문법 마스터 스쿨 (opens new window)