본문 바로가기
Swift 개발 이야기

Swift 의 Result 타입에 대해서 알아봅시다

by 방화동한량 2020. 5. 11.
728x90

굿데이 여러분

 

오늘은 Swift 에서 제공해주는 Result 에 대해서 간단히 알아보는 시간을 가져보도록 하겠습니다

 

일단 정의를 보면 이렇게 나와있네여

 

A value that represents either a success or a failure, including an associated value in each case.

 

성공이나 실패에 대한 값인데 각각의 케이스에 대한 연관된 값을 표현한다구 합니다.

 

그리고 각각의 케이스를 가지고 있다고 하니 당연히 enum 이겠져?

 

코드 안으로 들어가보면 역시나 당연하게도 enum 으로 만들어져 있습니다

 

@frozen public enum Result<Success, Failure> where Failure : Error {

    /// A success, storing a `Success` value.
    case success(Success)

    /// A failure, storing a `Failure` value.
    case failure(Failure)
    //...
    
    }

 

근데 앞에 @frozen 이라고 붙어있는데...이건 Objective-C 나 C 에서 넘어온 Enum 이 새로운 enum case 가 업데이트 되지 않는다는 것을 보증하는,,,? 그런 것이라고 합니다. 이 내용은 @unknown default 와 함께 나중에 다시 자세하게 알아보도록 할게여

 

자 그럼 Success 와 Failure 를 각각 정해서 내보낼 수 있는데, Failure 는 Error Protocol 을 준수해야 한다고 되어 있습니다.

 

Success 는 별도의 제약 조건이 없으니 원하는 결과값으로 정해주시면 되게씁ㄴ다

 

Error Protocol 을 준수하는 CustomError 라는 enum 을 하나 생성해주고, 여기서 에러를 관리하면 편하겠죠?

 

enum CustomError: Error {
    
    case basic
    case error(Error)
    case code(Int)
    
    var msg: String {
        switch self {
        case .basic:
            return "DEFAULT Error"
        case .error(let err):
            return err.localizedDescription
        case .code(let code):
            return "\(code) Error"
        }
    }
}

 

자 이제 Result 를 사용해보게씁니다

 

Result 는 이제 API 통신할 때 자주 사용되는데여 성공했을땐 success, 실패해서 error 가 리턴되는 경우엔 Failure 를 사용해주시면 됩니다

 

간단한 Network 관련된 Singleton 을 만들어주시고  URLSession 을 사용해서 만들어보면 아래처럼 나오게 됩니다.

class NetworkManager {

	static let shared = NetworkManager()
    
    private init() {}

	func requestURLSession<T: Decodable>(completion: @escaping (Result<T, CustomError>)->()) {
        
        var request = URLRequest(url: URL(string: "https://localhost:8080")!)
        request.method = .get

        URLSession(configuration: .default).dataTask(with: request) { (data, res, err) in
            
            if let error = err {
                completion(.failure(.error(error)))
            } else if let data = data {
                let jsonDecoder = JSONDecoder()
                if let decoded = try? jsonDecoder.decode(T.self, from: data) {
                    completion(.success(decoded))
                } else {
                    completion(.failure(.basic))
                }
            }
            
        }.resume()
        
    }

}



 

T 는 Decodable 을 준수하는 친구입니다 왜냐하면 나중에 결과를 jsonDecoder 를 써서 변환시킬거거등여

 

통신 이후 error 자체가 떨어지게 되면 result error 를 그대로 반환하면 되고

성공 시에도 json Decoding 이 제대로 성공했을 때에만 result Success 를 반환합니다

 

만약 decoding 이 실패한다면 역시 에러를 리턴해줍니다

 

이제 만들어진 네트워크 함수를 뷰컨트롤러에서 아래처럼 구현해주시면 성공/실패에 따라 원하는 값을 보여줄 수 있겠죵?

       NetworkManager.shared.requestURLSession { (result: Result<String, CustomError>) in
            
            switch result {
                
            case .success(let value):
                print(value)
            case .failure(let error):
                print(error.localizedDescription)
            }
            
        }

 

여기서 유의해야할 것은 Result<T, CustomError> 부분에서 반환될 T 를 핸들러 안에서 정의를 해주셔야 한다는 점입니다.

 

만약 String 이 Decodable 을 준수하지 않은 타입이었다면 오류가 발생했겠죠?

 

이렇게 Result 를 이용해서 간단하게 API 통신 값을 처리하는 법을 알아보았습니다

 

궁금한 점 있으시면 편하게 말씀해주세여

 

그럼 다음에 또 만나요 여러분 안녕~~~~