HIT해

[Swift 기초문법 - 17] Error 본문

Swift/Swift 기초문법

[Swift 기초문법 - 17] Error

힛해 2024. 7. 12. 01:43
728x90

Swift에서 Error 프로토콜은 오류 처리를 위한 표준 인터페이스를 제공한다. Swift의 오류 처리 모델은 명확하고 안전하게 오류를 처리할 수 있도록 설계되어 있다. 이번 포스팅에서는 Swift의 Error 프로토콜, 오류 처리 방법, 그리고 커스텀 오류 타입을 만드는 방법에 대해 알아보겠다.

Swift의 Error 프로토콜

Swift에서는 오류를 나타내기 위해 Error 프로토콜을 사용한다. 이 프로토콜은 빈 프로토콜로, 특별한 요구사항이 없다. 즉, Error 프로토콜을 채택하기만 하면 어떤 타입이든지 오류로 사용할 수 있다.

enum NetworkError: Error {
    case badURL
    case requestFailed
    case unknown
}

위 예제에서 NetworkError는 Error 프로토콜을 채택한 열거형(enum)으로, 여러 종류의 네트워크 오류를 정의하고 있다.

오류 던지기와 잡기

Swift에서 오류를 던지기 위해서는 throw 키워드를 사용한다. 오류를 던질 수 있는 함수는 throws 키워드를 사용하여 선언해야 한다. 오류를 처리하기 위해서는 do-catch 구문을 사용한다.

func fetchData(from url: String) throws -> String {
    guard url != "" else {
        throw NetworkError.badURL
    }

// 네트워크 요청을 시뮬레이션하는 코드
    let success = Bool.random()
    if success {
        return "데이터를 성공적으로 가져왔습니다."
    } else {
        throw NetworkError.requestFailed
    }
}

do {
    let data = try fetchData(from: "")
    print(data)
} catch NetworkError.badURL {
    print("잘못된 URL입니다.")
} catch NetworkError.requestFailed {
    print("요청이 실패했습니다.")
} catch {
    print("알 수 없는 오류가 발생했습니다: \\(error)")
}

위 예제에서 fetchData 함수는 URL이 빈 문자열인 경우 NetworkError.badURL 오류를 던진다. do-catch 구문을 사용하여 오류를 잡고, 각 오류에 대해 적절한 처리를 할 수 있다.

 

import UIKit

enum ErrorList : Error {
    case numberMismatch
    case nameMismatch
}

func guessMyName(name input : String) throws{
    print("called guess name")
    if(input != "힛해"){
        print("틀립니다")
        throw ErrorList.nameMismatch
    }
    print("맞았습니다")
}

do{
    try guessMyName(name: "ㅇ")
}catch{
    print(error)
}

 

이렇게 하면 에러에서 함수 호출이 종료되고 에러가 무엇인지 catch문에서 볼 수 있다

 

실행결과

 

이때 try? 를 하면 에러를 안볼 수 있다.

 

Result 타입을 사용한 오류 처리

Swift 5에서는 Result 타입을 도입하여 더 간결하고 명확하게 오류를 처리할 수 있다. Result 타입은 성공과 실패를 모두 표현할 수 있는 열거형이다.

func fetchData(from url: String) -> Result<String, NetworkError> {
    guard url != "" else {
        return .failure(.badURL)
    }
    
    let success = Bool.random()
    if success {
        return .success("데이터를 성공적으로 가져왔습니다.")
    } else {
        return .failure(.requestFailed)
    }
}

let result = fetchData(from: "")

switch result {
case .success(let data):
    print(data)
case .failure(let error):
    switch error {
    case .badURL:
        print("잘못된 URL입니다.")
    case .requestFailed:
        print("요청이 실패했습니다.")
    case .unknown:
        print("알 수 없는 오류가 발생했습니다.")
    }
}

위 예제에서 fetchData 함수는 Result 타입을 반환하며, 성공 시 데이터 문자열을, 실패 시 NetworkError를 반환한다. switch 구문을 사용하여 결과를 처리할 수 있다.

 

Return 값과 에러를 같이 내보내고 싶을 때

아래와 같이 코드를 만들면 된다!

// option + command + /


/// <#Description#> 메소드에 대한 설명
/// - Parameter input: input 값이 무엇인지
/// - Returns: return되는 건 무엇인지
func guessMyNumber(num input : Int) throws -> Bool{
    print("called guess name")
    if(input != 10){
        print("틀립니다")
        throw ErrorList.numberMismatch
    }
    print("맞았습니다")
    return true
}

do{
    let receivedValue = try guessMyNumber(num: 9)
}catch{
    print(error)
}

 

실행결과

 

만약 매개변수로 10이 들어간다면 값의 반환이 잘 될 것이다.

 

커스텀 오류 타입

사용자 정의 오류 타입을 만들 때는 주로 열거형(enum)을 사용한다. 각 오류 케이스에 관련 데이터를 추가할 수도 있다.

swiftenum FileError: Error {
    case fileNotFound(String)
    case unreadable
    case encodingFailed
}

func readFile(named fileName: String) throws -> String {
    if fileName == "missing.txt" {
        throw FileError.fileNotFound(fileName)
    } else if fileName == "unreadable.txt" {
        throw FileError.unreadable
    } else {
        return "파일 내용을 성공적으로 읽었습니다."
    }
}

do {
    let content = try readFile(named: "missing.txt")
    print(content)
} catch FileError.fileNotFound(let fileName) {
    print("\\(fileName) 파일을 찾을 수 없습니다.")
} catch {
    print("알 수 없는 오류가 발생했습니다: \\(error)")
}

위 예제에서 FileError는 파일 관련 오류를 나타내는 사용자 정의 오류 타입이다. readFile 함수는 파일 이름에 따라 적절한 오류를 던진다.

결론

Swift의 Error 프로토콜과 관련된 기능들은 오류를 명확하고 안전하게 처리할 수 있도록 도와준다. do-catch 구문, Result 타입, 그리고 커스텀 오류 타입을 통해 다양한 방식으로 오류를 처리할 수 있다. 이를 통해 더 견고하고 유지보수하기 쉬운 코드를 작성할 수 있다.