티스토리 뷰

Result

어떤 결과값이 성공 or 실패로 나뉜다면 Result로 쓰면 좋음.

 

기본코드⬇️

더보기
class ViewController: UIViewController {
    
    let centerLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
    }
}

// MARK: -URLSession
extension ViewController {
    func setUI() {
        setConstraints()
        setAttributes()
    }
    
    func setConstraints() {
        view.addSubview(centerLabel)
        centerLabel.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            centerLabel.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
            centerLabel.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor),
            centerLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            centerLabel.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
        ])
    }
    
    func setAttributes() {
        centerLabel.textColor = .black
        centerLabel.textAlignment = .center
        centerLabel.numberOfLines = 0
        centerLabel.text = "Test"
    }
}

 

Result 타입으로 통신 메서드 만들기

 

1. 정의

extension ViewController {
    
    private func getQuote(completion: @escaping (Result<Quote, Error>) -> Void) {
        let url = URL(string: "https://api.quotable.io/random")
        
        URLSession.shared.dataTask(with: url!) { data, response, error in
            guard error == nil else {
                print("error")
                return
            }
            
            guard let response = response as? HTTPURLResponse, (200..<300).contains(response.statusCode) else {
                print("response")
                return
            }
            
            guard let data = data else {
                return
            }
            
            do {
                let quote = try JSONDecoder().decode(Quote.self, from: data)
                //🍎 성공일 때
                completion(.success(quote))
            } catch {
                //🍎 실패일 때
                completion(.failure(error))
            }
            
        }.resume()
    }
}

 

2. 사용

class ViewController: UIViewController {
    
    let centerLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
        
        getQuote { [weak self] result in
        
            switch result {
            case .success(let quote):
                DispatchQueue.main.async {
                    self?.centerLabel.text = "성공\n \(quote.content)"
                }
                
            case .failure(let error):
                DispatchQueue.main.async {
                    self?.centerLabel.text = "실패\n \(error)"
                }
            }
        }
    }
}

 


 

 

Custom Error 만들기

 

1. ⭐️ 반드시 Error protocol을 채택해야 함

//Error protocol을 채택해야 함
enum NetworkError: Error {
    case badUrl
    case badResponse
    case communicationError
    case decodeFailed
    case noData
    // case는 얼마든지 늘리고 줄여도 됨
}

 

custom Error protocol을 채택해서 메서드 구현하기

    private func getQuote(completion: @escaping (Result<Quote, NetworkError>) -> Void) {
        let url = URL(string: "https://api.quotable.io/random")
        URLSession.shared.dataTask(with: url!) { data, response, error in
            guard error == nil else {
            	//🍎
                completion(.failure(.communicationError))
                return
            }

            guard let response = response as? HTTPURLResponse, (200..<300).contains(response.statusCode) else {
                //🍎
                completion(.failure(.badResponse))
                return
            }

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


            do {
                let quote = try JSONDecoder().decode(Quote.self, from: data)
                //🍎
                completion(.success(quote))
            } catch {
                print(error)
            }

        }.resume()
    }

 

2. 메서드 사용하기 (위와 동일)

class ViewController: UIViewController {
    
    let centerLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
        
        getQuote { [weak self] result in
        
            switch result {
            case .success(let quote):
                DispatchQueue.main.async {
                    self?.centerLabel.text = "성공\n \(quote.content)"
                }
                
            case .failure(let error):
                DispatchQueue.main.async {
                    self?.centerLabel.text = "실패\n \(error)"
                }
            }
        }
    }
}

 


custom Error를 LocalizedError와 사용하기

 

1. Error 확장

import Foundation


//Error protocol을 채택해야 함
enum NetworkError: Error {
    case badUrl
    case badResponse
    case communicationError
    case decodeFailed
    case noData
    // case는 얼마든지 늘리고 줄여도 됨
}

// localizedDescription를 잘 작성해두면 error를 잘 파악할 수 있음
extension NetworkError: LocalizedError {
    var errorDescription: String? {
        switch self {
        case .badUrl:
            return "badUrl 오류입니다."
        case .badResponse:
            return "badResponse 오류입니다."
        case .communicationError:
            return "communicationError 오류입니다."
        case .decodeFailed:
            return "decodeFailed 오류입니다."
        case .noData:
            return "noData 오류입니다."
        }
    }
}

 

2. 사용

class ViewController: UIViewController {
    
    let centerLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
        
        getQuote { [weak self] result in
            print(result)
            switch result {
            case .success(let quote):

                DispatchQueue.main.async {
                    self?.centerLabel.text = "성공\n \(quote.content)"
                }
            case .failure(let error):
                DispatchQueue.main.async {
                	//🍎
                    self?.centerLabel.text = "실패\n \(error.localizedDescription)"
                }
            }
        }
    }
}

 

 

 


Throws

 

do-catch를 언제 쓸 것인가? 메서드를 사용할 때 쓰고자 한다면!

이렇게 사용하면 메서드 구현부가 아닌 메서드 실행할 때 에러처리를 하게 됨

 

1. 메서드 구현

throws 함수는 try 키워드를 적어줘야 함

    private func throwingGetQuote(completion: @escaping (Result<Data, NetworkError>) -> Void) {
        let url = URL(string: "https://api.quotable.io/random")!
        
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard error == nil else {
                completion(.failure(.communicationError))
                return
            }
            
            guard let response = response as? HTTPURLResponse, (200..<300).contains(response.statusCode) else {
                completion(.failure(.badResponse))
                return
            }
            
            guard let data = data else {
                completion(.failure(.noData))
                return
            }
            
            completion(.success(data))
            
        }.resume()
    }
    private func decodedData(data: Data) throws -> Quote {
        return try JSONDecoder().decode(Quote.self, from: data)
    }

 

 

2. 사용할 때

class ViewController: UIViewController {
    
    let centerLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
        
        throwingGetQuote { [weak self] result in
            switch result {
            case .success(let data):
                do {
                    let quote = try self?.decodedData(data: data)
                    DispatchQueue.main.async {
                        self?.centerLabel.text = "성공\n \(quote?.content)"
                    }
                } catch {
                    print("network error")
                }
                
            case .failure(let error):
                DispatchQueue.main.async {
                    self?.centerLabel.text = "실패\n \(error.localizedDescription)"
                }
            }
        }
    }
}

 

 


 

Error를 switch문으로 처리도 가능

class ViewController: UIViewController {
    
    let centerLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
        
        throwingGetQuote { [weak self] result in
            switch result {
            case .success(let data):
                do {
                    let quote = try self?.decodedData(data: data)
                    DispatchQueue.main.async {
                        self?.centerLabel.text = "성공\n \(quote?.content)"
                    }
                } catch {
                    print("network error")
                }
                
            case .failure(let error):
            	//🍎 error 분기처리 
                switch error {
                case .badResponse:
                    print("badResponse error")
                case .badUrl:
                    print("badUrl error")
                case .communicationError:
                    print("communicationError error")
                case .noData:
                    print("noData error")
                case .decodeFailed:
                    print("decodeFailed error")
                }
            }
        }
    }
}
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크