본문 바로가기
스파르타코딩 클럽/기초

Swift | do, catch, try 이해하기(feat. Result Type)

by UDDT 2025. 4. 20.

에러 처리 방법 Lv1 : if문

    코드를 작성하다보면, 에러처리를 해야할 때가 있다

   개발을 할 때 처음의 error 처리는 조건문과 print문을 사용하여 처리한다.

let password = "123456"

func checkAnswer(_ input: String) {
    if input == password {
        print("로그인 성공")
    } else {
        print("로그인 실패")
    }
}


checkAnswer("123")

 

에러 처리 방법 Lv2: guard문

    이후 guard문을 배우게 되면 guard문을 사용하고 싶어진다.

let password = "123456"

func checkAnswer(_ input: String) {
    guard input == password else {
        print("로그인 실패")
        return
    }
    print("로그인 성공")
}


checkAnswer("123")

 

 에러 처리 방법 Lv3: do, try, catch문

    조금 더 심도있게 에러를 처리할 때, 우리는 do, try, catch문을 사용할 수 있다.

 1. do, try, catch를 모두 사용하는 방법

// 열거형으로 CustomError 만들기
enum CustomError: Error {
    case tooShortInput
    case tooLongInput
    case wrongInput
}

// 입력의 유효성 검사
func validate(_ input: String) throws -> Bool {
    if input.count < 6 {
        throw CustomError.tooShortInput
    } else if input.count > 8 {
        throw CustomError.tooLongInput
    } else {
        // 유효성 검사가 끝난 값만 정답 확인
        return try checkAnswer(input)
    }
}

// 유효성 검사가 끝난 값만 정답 확인
func checkAnswer(_ input: String) throws -> Bool {
    if input == "123456" {
        return true
    } else {
        throw CustomError.wrongInput
    }
}

// do, try, catch 사용
do {
    let isCorrect = try validate("123456")
    if isCorrect {
        print("정답입니다.")
    }
} catch {
    print(error)
}

 

    try - catch는, 에러를 처리하기 위한 구문으로

   throw 구문을 활용하여 말 그대로 에러를 던져준다

// do, try, catch문의 기본 형태
do {
	try 오류 발생 가능 코드
} catch 오류 패턴 {
	처리 코드
}
do {
    let isCorrect = try validate("123466")
    if isCorrect {
        print("정답입니다.")
    }
} catch CustomError.wrongInput {
    print("비밀번호가 틀렸습니다.")
}

 

  기본 형태를 따라 위의 코드처럼 작성할 수도 있다.

 

 2. try만 단독으로 사용하는 방법-1(try?)

let isCorrect = try? validate("123456")
if isCorrect == nil {
    print("로그인 실패")
} else {
    print("로그인 성공")
}

 

  위 코드처럼 try?를 사용하면, Optional 값으로 처리하여 에러가 발생할 때는 값을 nil로 만들 수도 있다. 

  값이 nil로 반환되기 때문에 do, catch를 할 필요가 없다.

 

 3. try만 단독으로 사용하는 방법-2(try!)

let isCorrect = try! validate("123456")
if isCorrect {
    print("로그인 성공")
}

 

   단 위의 경우에는 isCorrect가 nil일 때 크래시가 발생하므로, 값에 오류가 없음을 확신할 때만 사용 그냥, 사용하지 말도록 하자

 

 에러 처리 방법 Lv4: Result Type

    https://developer.apple.com/documentation/swift/result

 

Result | Apple Developer Documentation

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

developer.apple.com

 

   Apple Docs에 따르면, Result Type은 다음과 같다

A value that represents either a success or a failure, including an associated value in each case.
성공 또는 실패 케이스를 나타내는 값으로, 각각의 케이스의 연관 값을 포함합니다.
@frozen
enum Result<Success, Failure> where Failure : Error, Success : ~Copyable

 

// 열거형으로 CustomError 만들기
enum CustomError: Error {
    case tooShortInput
    case tooLongInput
    case wrongInput
}

// 입력의 유효성 검사
func validate(_ input: String) throws -> Bool {
    if input.count < 6 {
        throw CustomError.tooShortInput
    } else if input.count > 8 {
        throw CustomError.tooLongInput
    } else {
        // 유효성 검사가 끝난 값만 정답 확인
        return try checkAnswer(input)
    }
}

// 유효성 검사가 끝난 값만 정답 확인
func checkAnswer(_ input: String) throws -> Bool {
    if input == "123456" {
        return true
    } else {
        throw CustomError.wrongInput
    }
}

// do, try, catch 사용
do {
    let isCorrect = try validate("123456")
    if isCorrect {
        print("정답입니다.")
    }
} catch {
    print(error)
}

 

  위의 코드를 Result Type으로 변경해보면 아래의 코드처럼 변경할 수 있다.

enum CustomError: Error {
    case tooShortInput
    case tooLongInput
    case wrongInput
}

func validate(_ input: String) -> Result<Bool, CustomError> {
    if input.count < 6 {
        return .failure(.tooShortInput)
    } else if input.count > 8 {
        return .failure(.tooLongInput)
    } else {
        return .success(true)
    }
}

let checkAnswer = validate("123456")
switch checkAnswer {
case .success(let data):
    print(data)
case .failure(let error):
    print(error)
}

 

   비교해보자면,

// throws를 사용할 때
func validate(_ input: String) throws -> Bool {
    if input.count < 6 {
        throw CustomError.tooShortInput
    } else if input.count > 8 {
        throw CustomError.tooLongInput
    } else {
        // 유효성 검사가 끝난 값만 정답 확인
        return try checkAnswer(input)
    }
}

// Result Type을 사용할 때
func validate(_ input: String) -> Result<Bool, CustomError> {
    if input.count < 6 {
        return .failure(.tooShortInput)
    } else if input.count > 8 {
        return .failure(.tooLongInput)
    } else {
        return .success(true)
    }
}

 

  throws 함수를 사용할 때 : 에러를 던져주고 유효성 검사가 끝난 값만 checkAnswer를 try (return 되는 값이 Bool)

  Result를 사용할 때 : 실패 케이스와 성공 케이스로 return이 가능 (return 되는 값이 성공 또는 실패)

 

// throws를 사용할 때
func checkAnswer(_ input: String) throws -> Bool {
    if input == "123456" {
        return true
    } else {
        throw CustomError.wrongInput
    }
}

do {
    let isCorrect = try validate("123456")
    if isCorrect {
        print("정답입니다.")
    }
} catch {
    print(error)
}

//Result Type을 사용할 때
let checkAnswer = validate("123456")
switch checkAnswer {
case .success(let data):
    print(data)
case .failure(let error):
    print(error)
}

 

Result Type과 do, try, catch의 차이

     Result Type과 do - try - catch는 비슷한 매커니즘을 가지고 있는거 같은데,

   그럼 어떤 점이 다를까?

구 분 Result Type do - try - catch
에러 전달 방식 값(Value)로 에러를 전달함 throws 함수 호출 시 에러를 던짐(throw)
처리 방식 switch문으로 success와 failure를 구분함 do 블럭 안에서 try하고, catch 블럭에서 에러 처리

 

  - Result Type을 사용하는 비동기 작업 예시

func loadData(completion: (Result<Data, Error>) -> Void) {
    // 네트워크 처리 후 에러를 다룰 때
    completion(.failure(CustomError.tooShortInput))
}

 

  이해할 수 있었던 내용은

  1. Result Type은 succes case와 failure case가 명시되어 있어서 가독성이 좋다는 것과

  2. Result Type은 비동기 작업을 할 때 사용하고, do - try - catch는 간단한 작업을 할 때 사용한다는 점

  정도..?를 이해할 수 있었다.

  세부사항은 더 공부가 필요하겠지만...

 

최근댓글

최근글

skin by © 2024 ttuttak