swift

[swift] Result Type 알아보기

순진이 2022. 2. 3. 17:37

지난 번 Alamofire 글을 쓰면서 만났던 Result Type이 hoxy 기억나시나요?

오늘은 Result Type에 대해서 알아보고자 해요.

 

 

예전에 앨런님께 배우긴 하였으나, 늘 그렇듯이 중요한 건 기억이 안나니까요 ㅎㅎ

스따뚜🥴

 


Result Type은 에러를 처리할 때 사용하는 하나의 에러 처리 방법이에요.

에러를 throws하는 경우, do-catch로 처리하는 번거로움이 있지만 Result Type의 경우, 성공(success)과 실패(failure) 두 가지로 나눠 처리할 수 있기 때문에 훨씬 명확해요.

 

 

Result Type의 공식문서 정의를 보면, 아래와 같아요.

 

 

열거형으로 선언된 Result Type에는 2개의 값이 있습니다.

case success와 case failure이죠.

enum Result<Success, Failure> where Failure: Error {
	case sucess
	case failure
}

 

1. Error 프로토콜 채택

where 뒤를 보면 Failure은 Error 프로토콜을 채택해야 한다네여!!

Error 프로토콜은 '던져질 수 있는 에러를 표현하는 타입'이랍니다.

 

 

 

 

 

Failure는 반드시 이 Error protocol을 채택하는 타입이어야 하는거져!


2. success, failure의 타입

success와 failure은 제네릭으로 선언되어 있기 때문에 어떤 타입의 연관값이든 담을 수 있습니다.

아래처럼 말이죠.

Result<Bool, MyError>
Result<String, MyError>
Rsult<Int, HeightError>

일단 무슨 말인지 헷갈리니까 예시를 한 번 볼게요.

 

 

우선 Error 프로토콜을 채택하는 MyError를 하나 선언해줍니다.

case는 max와 min으로 만들주고요.

enum MyError: Error {
    case max
    case min
}

 

 

그리고 Result Type을 리턴하는 함수 하나를 만들어줄게요.

2번에서 말했듯이 success와 failure은 어떤 타입이든 상관없기 때문에, 제가 선언해주면 돼요.

이번에는 String타입으로 할게요.

 

 

success는 String타입, failure는 위에서 만든 MyError타입이에욧.

func getData(num: Int) -> Result<String, MyError> {
    if 0 < num && num <= 10 {
        return .success("성공")
    } else if num < 0 {
        return .failure(.min)
    } else {
        return .failure(.max)
    }
}

 

 

1~10까지 숫자는 성공,

0보다 작으면 min에러, 10보다 크면 max에러를 줘볼게요.

 

 

그리고 result라는 상수를 만들어서 함수를 할당해봅니다.

파라미터의 값을 다양하게 줘볼게요!

let result = getData(num: 10)

//success("성공")
let result = getData(num: -4)

//failure(__lldb_expr_16.MyError.min)
let result = getData(num: 13)

//failure(__lldb_expr_18.MyError.max)

 

제가 선언한 Result Type으로 잘 나오는 걸 알 수 있죠?


Result Type은 success와 failure로 딱 나뉘기 때문에 switch 문과 함께 사용하는 경우가 많아요.

let result = getData(num: 13)

switch result {
case .success(let message):
    print("성공: \(message)")
case .failure(let error):
    print("실패: \(error)")
}

// 실패: max

 

result를 눌러보면 위에서 선언한 Result Type이구요.

 

 

success의 연관값인 message의 타입을 보면 String 타입인 걸 알수 있어요.

 

확실히 do-catch문으로 사용할 때보다 간편하지 않나요?

🤢좋아

 


그러면 지난 번에 만들었던 Alamofire의 예제로 다시 돌아볼게요.

우리에 Alamofire로 받았던 response를 option키를 눌러서 보면 아래와 같은 타입이에요.

 

 

성공적으로 데이터를 받아오면 WeatherManager 타입을 리턴하고, 실패할 경우에는 AFError를 리턴하는거죠.

 

 

 

AFError를 찾아보면 역시나 Error 프로토콜을 채택한 걸 알 수 있쥬?

 

 

5번째 줄을 보면 이 Result Type을 switch문으로 처리한 게 보이져?

넘나리 간편하기 때문이져!

    @objc func getTempTapped(_ sender: UIButton) {
        let request = AF.request("https://api.openweathermap.org/data/2.5/weather?appid=cc67530774268e4f6e4250794df2dca2&units=metric&q=seoul")
        request.validate().responseDecodable(of: WeatherManager.self) { response in
            switch response.result {
            case .success(let weather):
                self.mainLbl.text = String(weather.main.temp)
            case .failure(let error):
                print(error)
            }
        }
    }

여기서 success의 연관값인 weather 또한 위에서 선언한 WeatherManager 타입인 게 보이져?


아주 유용해 보이는 Result Type!

잘 쓸 수 있겠져?

 

오늘도 잘못된 게 있으면 많이들 알려주십셔 슨배님덜!! 🙏🏻