본문 바로가기
Programming/Swift

[iOS Swift] 스위프트에서 Error Handling 하는 방법

by 개발자 염상진 2024. 1. 15.

Swift Error Handling

안녕하세요. 개발자 AboutTech입니다. 이번 포스팅에서는 스위프트 언어를 사용한 아이폰 앱 개발에서 에러를 어떻게 처리할 수 있는지 알아보도록 하겠습니다. 모든게 완벽한 코딩이라면 에러가 발생할 일도 없을 것입니다. 하지만 현실에서는 앱을 사용하던 중에 네트워크가 꺼질 수도 있고, 사용자가 예상치 못한 지점에서 앱이 정상작동하지 않는 경우가 무수히 많습니다.

개발자도 사용자도 예상하지 못한 에러가 발생했을 때 예기치 못한 심각한 오류로 사용자 경험이 훼손되지 않게 하기 위해서는 적절한 그리고 우아한 에러 처리가 필수입니다. 아이폰 앱 개발에 사용되는 스위프트에서는 에러 핸들링 작업을 위해 guard, defer, do-catch, 그리고 throwing method 기능을 제공하면서 한결 쉽게 에러 핸들링을 할 수 있도록 지원하고 있습니다. 

 

 

 

 

 

Throwing vs Catching

Swift 언어에서 에러를 처리하는 방법은 크게 2가지로 구분됩니다. 먼저 함수 내에서 에러가 발생한 경우 에러를 인위적으로 발생시키는 Throwing이 첫번째 입니다. 에러를 던지는 경우에는 Error 프로토콜을 준수하는 값으로 다음 로직을 처리할 수 있는 코딩이 필요하겠죠?

두번째 에러 핸들링 방법은 실제로 에러가 되었을 때 에러를 Catching 하는 방법입니다. 이 때 사용하는 키워드가 do - catch 문입니다. 

 

 

 

Error 만들기

앱에서 에러가 발생하는 가장 흔한 상황은 인터넷 연결이 원활하지 못한 엘레베이터나 지하철에서 핸드폰을 사용하는 경우입니다. 이 때 다운로드를 하던 중 인터넷이 끊기게 되면 파일 전송이 완료되지 못하는 경우가 생깁니다. 만약 파일이나 동영상이 스트리밍 파이프라인으로 들어오다가 인터넷이 끊기면 전체 파일이 전송되지 못했기 때문에 이에 대한 로직을 구성해줘야 합니다. 

먼저 파일 전송 에러가 발생했을 때의 상황을 열거형 enum으로 구현합니다. 파일이 없는 경우 부터 연결이 끊어졌을 때 까지 다양한 상황을 열거형으로 구성합니다. 

enum FileTransferError: Error {
    case fileNotFound
    case permissionDenied
    case connectionLost
    case fileCorrupted
}

이제 함수 내에서 에러가 발생하는 경우 에러를 던져야(throwing) 합니다. 에러를 던지는 함수를 제작합니다. 함수 내에서 에러를 던지기 위해서는 if - else 분기문을 처리했을 때 보다 guard 구문을 사용하는 것이 빠르고 편리합니다. 

func simulateFileTransfer(connectionExists: Bool) throws {
    // 연결이 끊겨서 에러가 나는 경우
    guard connectionExists else {
        throw FileTransferError.connectionLost
    }

    // 에러가 나오지 않았을 때 정상 코드
}

마지막으로 에러를 던지는 함수에서 에러가 발생했을 때 던진 에러를 잡아주는 Catching 구문을 완성합니다. 이 때 에러 메서드를 던질 수도 있는 함수를 호출할 때는 try 키워드를 사용해주셔야 합니다. 

 

 

 

func handleFileTransfer() {
    do {
        try simulateFileTransfer(connectionExists: true)
        print("File transfer successful.")
    } catch FileTransferError.connectionLost {
        print("Connection lost during file transfer.")
    } catch {
        print("An unexpected error occurred: \(error)")
    }
}

마지막 catch 문은 catch all의 의미를 가지고 있습니다. 즉 앞선 에러를 모두 처리하지 못하는 예외 상황의 예외 상황이 나올 경우에 마지막까지 에러를 처리할 수 있는 구문입니다. 

에러를 catching 할 때 do-catch 구문을 사용할 필요 없이 절대로 에러가 발생하지 않는다고 고려되는 에러 쓰로잉 메서드를 사용하는 경우에는 (!) 마크를 사용해 에러 캐칭을 비활성화할 수 있습니다. 하지만 모든 에러를 100% 예상하기는 불가능하기 때문에 가급적 사용하지 않는 것을 권장드립니다. 

func handleFileTransfer() {
    try! simulateFileTransfer(connectionExists: true)
}

 

let error로 에러 객체에 접근하기

catch 문에서 에러 객체에 직접적으로 접근하기 위해서는 let error로 상수로 에러 객체를 사용할수도 있습니다. 

func handleFileTransfer() {
    do {
        try simulateFileTransfer(connectionExists: true)
        print("File transfer successful.")
    } catch let error as FileTransferError {
        switch error {
        case .fileNotFound:
            print("File not found: \(error.localizedDescription)")
        case .permissionDenied:
            print("Permission denied: \(error.localizedDescription)")
        case .connectionLost:
            print("Connection lost during file transfer: \(error.localizedDescription)")
        case .fileCorrupted:
            print("File corrupted: \(error.localizedDescription)")
        }
    } catch {
        print("An unexpected error occurred: \(error.localizedDescription)")
    }
}

 

 

 

 

defer 구문으로 에러 캐칭 유예하는 방법

Swift에서 에러 처리는 try, do-catch로 간단하게 처리할 수 있습니다. 다만 에러 처리를 하는 catching 과정에서 특수한 로직을 처리하고 제어권을 반환하기 위해서 defer 구문을 처리할 수 있습니다. 예를 들어 인터넷 연결이 끊어졌을 때 불완전한 파일을 삭제하는 로직이 필요할 수 있습니다. 

func handleFileTransfer() {

    defer {
        print("임시 파일을 제거합니다.)
    }

    do {
        try simulateFileTransfer(connectionExists: true)
        print("File transfer successful.")
    } catch let error as FileTransferError {
        switch error {
        case .fileNotFound:
            print("File not found: \(error.localizedDescription)")
        case .permissionDenied:
            print("Permission denied: \(error.localizedDescription)")
        case .connectionLost:
            print("Connection lost during file transfer: \(error.localizedDescription)")
        case .fileCorrupted:
            print("File corrupted: \(error.localizedDescription)")
        }
    } catch {
        print("An unexpected error occurred: \(error.localizedDescription)")
    }
}

 

이번 포스팅에서는 Swift 에러처리하는 방법에 대해 알아보았습니다. 항상 자신의 코드가 완벽하게 구현될 것이라는 자부심을 가지는 것 보다는 예외 상황을 처리하고 유저가 겪게 되는 상황을 예상하고, 피드백을 받아 발생된 에러를 예외처리하는 습관을 가지도록 합시다. 

 

🚀️ 도움이 되셨다면 구독좋아요 부탁드립니다 👍️

 

 

 

[iOS Swift5] Collection, 배열과 딕셔너리, Set 기본

안녕하세요. AboutTech입니다. Swift에서 다양한 데이터와 객체들을 집합체로 묶어 관리할 수 있는 타입을 컬렉션이라고 합니다. 컬렉션 타입에는 대표적으로 배열과 딕셔너리가 있는데요 데이터들

about-tech.tistory.com

 

 

[iOS Swift5] 열거형 구조체 기본 기초

Swift에서 클래스만큼이나 자주 사용되는 타입이 바로 구조체입니다. 이번 포스팅에서는 클래스와 구조체를 비교하면서 SwiftUI를 활용한 iOS 앱 개발에 필요한 구조체와 열거형의 개념에 대해 간

about-tech.tistory.com

 

 

[iOS Swift5] 연산자와 표현식

Swift 연산자와 표현식 변수에 값을 할당하는 방법은 기본적으로 표현식을 따릅니다. 피연산자와 할당자 그리고 연산자를 통해 값을 생성하고 변수에 데이터를 저장할 수 있습니다. var number = 1 +

about-tech.tistory.com

 

 

댓글