Swift

Swift - 10. 에러 핸들링

iosos 2024. 1. 6. 17:22

 

 

에러 핸들링

  • 활성화된 인터넷 연결을 기반으로 동작하는 앱은 디바이스가 네트워크 신호를 잃는 것을 제어할 수 없음
  • 에러 처리를 해야 함
  • ex) 앱을 계속 사용하려면 인터넷 연결이 필요하다는 메시지 띄우기
  • 에러 처리 2단계
    1. iOS 앱의 메서드 내에서 원하는 결과가 나오지 않을 경우 에러 발생 (스로잉)
    2. 메서드가 던진 에러를 잡아서 처리
  • 에러를 던진 경우, 해당 에러는 에러의 특성을 식별하여 적절한 동작을 결정하는 데 사용되는 특정 에러 타입 중 하나가 됨
  • 에러 타입 값은 Error 프로토콜을 따르는 모든 값이 될 수 있음

 

 

 

에러 타입 선언

  • 원격 서버 파일을 전송하는 메서드가 있다고 하자.
  • 이 메서드는 여러 원인(네트워크 연결 x, 네트워크 속도 느림, 전송할 파일 찾지 못함)으로 인해 파일 전송에 실패 가능성 있음
  • → 이러한 에러는 다음과 같이 Error 프로토콜을 따르는 열거형 내에서 표현되도록 함
// 에러 타입 선언
enum FileTransferError : Error {
    case noConnection
    case lowBandwith
    case fileNotFound
}

→ 에러 타입 선언했으니 에러가 발생했을 때 사용 가능

 

 

 

에러 던지기

  • 메서드나 함수가 에러를 던질 수 있다는 것을 선언 할 때는 다음과 같이 throws 키워드 사용
// 에러 던지기
func transferFile() throws {
    
}

// 결과를 반환하는 메서드나 함수의 경우, throws 키워드는 반환 타입 앞에 위치 해야 함
func transferFile() throws -> Bool {
    
}

 

 

 

  • 오류가 발생할 때 에러를 던지는 코드 추가
  • 상태 값으로 제공되는 상수들을 선언 후, 메서드에 대한 guard 동작과 throw 동작 구현
let connectionOK = true
let connectionSpeed = 30.0
let fileFound = false

enum FileTransferError : Error {
    case noConnection
    case lowBandwith
    case fileNotFound
}

func fileTransfer() throws {
    
    guard connectionOK else {
        throw FileTransferError.noConnection
    }
    
    guard connectionSpeed > 30 else {
        throw FileTransferError.lowBandwith
    }
    
    guard fileFound else {
        throw FileTransferError.fileNotFound
    }
}

→ throw 구문과 guard 구문 결합하여 사용

  • guard 구문은 각 조건이 참인지 아닌지 검사
  • 거짓이라면 else 구문에 포함된 코드 실행

 

 

 

에러를 던지는 메서드와 함수 호출

  • 메서드 또는 함수가 에러를 던지도록 선언했다면 일반적인 방법으로는 호출 불가능
  • 이러한 메서드를 호출할 때는 try 구문을 붙여야 함
try fileTransfer()

 

 

  • try 구문을 이용하는 방법 외에도 던져진 모든 에러를 잡아서 처리하는 do-catch 구문 내에서 호출하는 방법
    • ex) fileTransfer() 메서드를 sendFile() 이라는 메서드 내에서 호출한다고 가정
    func sendFile() -> String {
        do {
            try fileTransfer()
        } catch FileTransferError.noConnection {
            return "No Network Connection"
        } catch FileTransferError.lowBandwith {
            return "File Trnasfer Speed too Low"
        } catch FileTransferError.fileNotFound {
            return "File Not Found"
        } catch {
            return "UnKnown Error"
        }
        
        return "Successul transfer"
    }
    • 에러 없이 성공하면 "Successul transfer" 리턴
    • 에러에 대한 패턴 매칭이 이뤄지지 않은 상태 "UnKnown Error" 리턴
    • → catch all 구문으로 앞선 catch 구문과 일치하지 않은 모든 에러를 처리 가능 ('catch { return "UnKnown Error" } ')
    • do-catch 구문은 가능한 모든 에러에 대해 처리할 수 있도록 구성되어야 하기 때문

 

 

에러 객체 접근

  • 메서드 호출이 실패하면 반드시 실패한 원인을 구별할 수 있는 MSError 객체가 반환됨
  • catch 구문에서 가장 필요한 것은 이 객체에 접근하여 적절한 동작을 실시하는 것
  • 새로운 파일 시스템 디렉터리를 생성하고자 할 때 catch 구문 내에서 여러 객체에 접근하는 방법을 보여줌
do {
    try filemgr.createDirectory(atPath: newDir, withIntermediateDirectories : true attributes: nil)
} catch let error {
    print("Error : \(error.localizedDesciption)")
}

 

 

 

 

에러 캐칭 비활성화

  • try! 구문 사용 → do-catch 구문 내에서 메서드가 호출되도록 감싸지 않아도 스로잉 메서드가 강제 실행
try! fileTransfer

→ 컴파일러에게 이 메서드 호출은 어떠한 에러도 발생하지 않을 것이라고 알려주는 것과 동일

에러가 발생한다면 런타임 에러 → 가급적 사용 x

 

 

 

defer 구문 사용하기

  • sendFile 메서드는 에러 처리하는 일반적인 시나리오
  • do-catch 구문에 있는 각각의 catch 절은 호출하는 메서드에게 제어권을 반환하기 위해 return 사용
  • 하지만, 에러의 종류와 상관없이 제어권을 반환하기 전에 어떤 별도 작업을 수행하는 게 효과적일 수 있음
  • ex) sendFile 메서드에서 제어권 반환 전 임시 파일을 지워할 경우 → defer 구문 사용
  • defer 구문은 메서드가 결과 반환하기 직전 수행되어야 하는 일련의 코드 지정
func sendFile() -> String {
    
    defer {
        removeTmpFiles()
        closeConnection()
    }
    
    do {
        try fileTransfer()
    } catch FileTransferError.noConnection {
        return "No Network Connection"
    } catch FileTransferError.lowBandwith {
        return "File Trnasfer Speed too Low"
    } catch FileTransferError.fileNotFound {
        return "File Not Found"
    } catch {
        return "UnKnown Error"
    }
    
    return "Succeccsul transfer"
}

→ 제어권 반환 전 removeTmpFiles, closeConnection 메서드 호출 됨

'Swift' 카테고리의 다른 글

Swift - 구조체 정의 (Decodable) - Codingkey 사용  (0) 2024.08.10
Swift - Xcode 프로젝트 생성  (0) 2024.06.24
Swift - 9. 배열과 딕셔너리  (1) 2024.01.06
Swift - 8. 프로퍼티 래퍼  (0) 2023.12.29
Swift - 7. 구조체  (0) 2023.12.28