[Swift] Result Type

임승섭·2023년 7월 12일
0

Swift

목록 보기
25/35

Result type을 활용한 에러 처리

  • 에러가 발생할 때, 외부로 throw하는 게 아니라,
    리턴 타입 자체를 Result type으로 구현해서,
    함수 실행의 성공과 실패의 정보를 함께 담아서 리턴한다

  • 실제 Result type의 내부 구현 - enum 타입. case 두개(success, failure). 연관값으로 정의
    enum Result<Success, Failure> where Failure : Error

// 에러 정의
enum HeightError: Error {    //에러 프로토콜 채택 (약속)
    case maxHeight
    case minHeight
}

// throwing함수 (앞에서 배운)
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
        }
    }
}

do {
    let _ = try checkingHeight(height: 200)
    print("놀이기구 타는 것 가능")
} catch {
    print("놀이기구 타는 것 불가능")
}


// throws로 던질 필요 없이, Result로 리턴한다
func resultTypeCheckingHeight(height: Int) -> Result<Bool, HeightError> {
    
    if height > 190 {
        return Result.failure(HeightError.maxHeight)
    } else if height < 130 {
        return Result.failure(HeightError.minHeight)
    } else {
        if height >= 160 {
            return Result.success(true)
        } else {
            return Result.success(false)
        }
    }
}

// 리턴값을 받아서 (try 키워드가 필요 없다. 바로 Result 타입으로 받는다)
let result = resultTypeCheckingHeight(height: 200)

// 처리 (굉장히 쉬워짐)
switch result {
case .success(let data):
    print("결과값은 \(data)입니다.")
case .failure(let error):
    print(error)
}

네트워킹 코드에서 Result type 활용

// 에러 정의
enum NetworkError: Error {
    case someError
}

// 기존 코드
func performRequest(with url: String, completion: @escaping (Data?, NetworkError?) -> Void) {	// 정상적인 경우는 Data 전달
    
    guard let url = URL(string: url) else { return }
    
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if error != nil {
            print(error!)                 // 에러가 발생했음을 출력
            completion(nil, .someError)   // 에러가 발생했으니, nil 전달
            return
        }
        
        guard let safeData = data else {
            completion(nil, .someError)   // 안전하게 옵셔널 바인딩을 하지 못했으니, 데이터는 nil 전달
            return
        }
    
    	// 모든게 정상적으로 처리되었을 때,
        completion(safeData, nil)		// 콜백함수 호출
        
    }.resume()
}

performRequest(with: "주소") { data, error in

    // 데이터를 받아서 처리
    if error != nil {
        print(error!)
    }
    
    // 데이터 처리 관련 코드
    
}



// Result type 사용
func performRequest2(with urlString: String, completion: @escaping (Result<Data,NetworkError>) -> Void) {	// 파라미터 두 개를 넣는게 아니고, Result type을 넣어준다
    
    guard let url = URL(string: urlString) else { return }
    
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if error != nil {
            print(error!)                     // 에러가 발생했음을 출력
            
            // completion(Result.failure(NetworkError.someError)) 생략해서 아래와 같이 사용
            completion(.failure(.someError))  // 실패 케이스 전달 (열거형 이름 생략)
            return
        }
        
        guard let safeData = data else {
            completion(.failure(.someError))   // 실패 케이스 전달
            return
        }
    
        completion(.success(safeData))      // 성공 케이스 전달
       
        
    }.resume()
}

performRequest2(with: "주소") { result in
    switch result {
    case .failure(let error):
        print(error)
    case .success(let data):
        // 데이터 처리 관련 코드
        break
    }
}

0개의 댓글