티스토리 뷰

728x90
반응형

Swift5의 Result Type을 사용하면 비동기 API쪽 코드(데이터 받아와서 디코딩해주는..)를 간단하고 명확하게 만들 수 있다 

[ 1 ] 그전에는..

 

1) 옵셔널로 구분 

    func fetchModel<T: Decodable>(completion: @escaping (T?) -> Void) {
        let url = URL(string: "...")!
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else {
                return completion(nil)
            }
            
            guard let model = try? JSONDecoder().decode(T.self, from: data) else {
                return completion(nil)
            }
            
            completion(model)
        }.resume()
    }

 

nil인지 아닌지 여부로 데이터가 잘 받아지고 디코딩도 잘 되었는지 확인했다 

  fetchModel { (model: SomeModel?) in
      if let model = model {
          print(model)
      }
  }

 

2) 더 나아가 에러까지 구체적으로 명시해서 구분 

    enum APIError: Error {
        case data
        case decodingJSON
    }
    
    func fetchModel<T: Decodable>(completion: @escaping (T?, APIError?) -> Void) {
        let url = URL(string: "...")!
        URLSession.shared.dataTask(with: url) { data, response, error in

            guard let data = data else {
                return completion(nil, .data)
            }
            
            guard let model = try? JSONDecoder().decode(T.self, from: data) else {
                return completion(nil, .decodingJSON)
            }

            completion(model, nil)
            
        }.resume()
    }

 

    fetchModel { (model: SomeModel?, error) in
        if let error = error {
            print(error)
        }

        if let model = model {
            print(model)
        }
    }

 

3) 더더 나아가 APIResult 라는 Enum을 정의해서 처리 

    enum APIResult<T> {
        case success(T)
        case failure(APIError)
        
        enum APIError: Error {
            case data
            case decodingJSON
        }
    }
    
    func fetchModel<T: Decodable>(completion: @escaping (APIResult<T>) -> Void) {
        let url = URL(string: "...")!
        URLSession.shared.dataTask(with: url) { data, response, error in

            guard let data = data else {
                return completion(.failure(.data))
            }

            guard let model = try? JSONDecoder().decode(T.self, from: data) else {
                return completion(.failure(.decodingJSON))
            }

            completion(.success(model))
            
        }.resume()
    }

 

    fetchModel { (result: APIResult<WeatherResult>) in
        switch result {
        case .success(let model):
            print(model)
        case .failure(let error):
            print(error)
        }
    }

 

[ 2 ] Result Type

Swift5는 standard library(표준 라이브러리)에 Result Type이 추가되었다

이제 위의 APIResult같은 enum을 따로 만들어주지 않아도 된다 : ) 

(https://github.com/apple/swift-evolution/blob/master/proposals/0235-add-result.md)

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)
}

 

    enum APIError: Error {
        case data
        case decodingJSON
    }
    
    func fetchModel<T: Decodable>(completion: @escaping (Result<T,APIError>) -> Void) {
        let url = URL(string: "...")!
        URLSession.shared.dataTask(with: url) { data, response, error in

            guard let data = data else {
                return completion(.failure(.data))
            }

            guard let model = try? JSONDecoder().decode(T.self, from: data) else {
                return completion(.failure(.decodingJSON))
            }

            completion(.success(model))
            
        }.resume()
    }

 

guard let 대신 do catch를 쓸 수도 있다 

    func fetchModel<T: Decodable>(completion: @escaping (Result<T,APIError>) -> Void) {
        let url = URL(string: "...")!
        URLSession.shared.dataTask(with: url) { data, response, error in

            guard let data = data else {
                return completion(.failure(.data))
            }

            do {
                let model = try JSONDecoder().decode(T.self, from: data)
                completion(.success(model))
            } catch {
                completion(.failure(.decodingJSON))
            }

        }.resume()
    }

 

    fetchModel { (result: Result<WeatherResult,APIError>) in
        switch result {
        case .success(let model):
            print(model)
        case .failure(let error):
            print(error)
        }
    }

 

 

 

 

+ Swift5 에 관해 더 읽어보기 

 

https://swift.org/blog/swift-5-released/

 

Swift 5 Released!

Swift 5 is now officially released!

swift.org

https://developer.apple.com/documentation/xcode_release_notes/xcode_10_2_release_notes/swift_5_release_notes_for_xcode_10_2

 

Swift 5 Release Notes for Xcode 10.2 | Apple Developer Documentation

Article Swift 5 Release Notes for Xcode 10.2 Update your code to use new language features and test your apps against changes. OverviewRead these notes when you’re writing Swift apps in Xcode 10.2.GeneralSwift 5 Runtime Support for Command Line Tools Packa

developer.apple.com

이 영상도 좋다...!! >___<

https://www.youtube.com/watch?v=_Iw4zf8gtqs

반응형
댓글