오늘의 Swift 상식 (Error Handling)

장국진
4 min readJun 18, 2019

--

에러 처리(Error Handling)란?

- 프로그램 내에서 에러가 발생한 상황에 대해 대응하고 이를 복구하는 과정

- swift에서는 런타임에 에러가 발생한 경우 이를 처리하기 위한 발생(throwig), 감지(catching), 전파(propagating), 조작(manipulating)을 지원하는 일급 클래스를 제공한다.

에러의 표시와 발생(Representing and Throwing Errors)

swift에서 에러는 Error 프로토콜을 따르는 타입의 값으로 표현된다. 비어있는 이 프로토콜은 에러 처리에 타입을 사용할 수 있음을 나타낸다. 특히 열거형은 에러를 그룹화하는데 적합하며, 에러에 대한 추가 정보를 제공한다.

아래 부터 예시로 드는 코드는 성인의 나이를 출력하는 코드다! 입력된 String이 숫자가 아니면 notInt 에러가 발생하고, 나이가 범위를 넘어가면 outOfRange(from: 20) 에러가 발생한다.

enum ErrorMessage: Error {
case outOfRange(from: Int)
case notInt
}

만약 열거형으로 에러를 그룹화했을 때 rawValue가 있다면 print 구문 사용 시 .rawValue를 붙여서 rawValue를 출력할 수 있다.

에러를 발생시킴으로써 기대하지 않았던 동작이 발생했고 작업을 계속 수행할 수 없다는 것을 알려줄 수 있다. 에러를 발생시키기 위해서는 throw 구문을 사용한다.

throw ErrorMessage.outOfRange(from: 20)

에러 처리(Handling Errors)

어떤 함수, 메소드 혹은 Initializer가 에러를 발생 시킬 수 있다는 것을 알리기 위해 throw 키워드를 함수 선언부의 파라미터 뒤에 붙인다. throw 키워드로 표시된 함수를 throwing function이라고 부르며, 만약 함수가 리턴 값을 명시했다면 throw 키워드는 리턴 값 표시 기호인 -> 전에 적으면 된다.

func adultAge(of text: String) throws -> Int

오직 throwing fuction만이 에러를 발생시킬 수 있다. 만약 throwing function이 아닌 함수에서 throw가 발생한다면 반드시 그 함수 내에서 throw에 대해 처리되어야 한다.

do-catch를 이용한 에러 처리(Handling Error Using do-catch)

do-catch 구문을 이용해 에러를 처리하는 코드 블럭을 작성할 수 있다. 만약 에러가 do 구문 내에서 발생한다면 발생하는 에러의 종류를 catch 구문으로 구분해 처리할 수 있다.

옵셔널 값으로 변환하기(Converting Error to Optional Values)

try?를 사용해 에러를 옵셔널 값으로 변환할 수 있다. 만약 에러가 try? 표현 내에서 발생한다면, 그 표현의 값은 nil이 된다. 위의 do-catch 문을 이와 같은 방법으로 변경하면 아래와 같다.

만약 adultAge()가 에러를 발생시키면 output은 nil이 되고, 그렇지 않으면 output은 함수의 리턴 값을 가진다. (값은 옵셔널로 바인딩)

try?는 발생하는 모든 에러를 같은 방법으로 처리하고 싶을 때 주로 사용한다.

에러 전파 차단(Disable Error Propagation)

함수나 매소드에서 에러가 발생되지 않을 것이라고 확신하는 경우 try!를 사용한다. 또한 runtime assertion을 사용해 에러가 발생하지 않도록 할 수 있다. 하지만 에러가 발생하면 런타임 에러가 발생하게 된다.

정말 절대 에러가 안 날 경우 사용하자! 하지만 그닥 추천하진 않는다. (어떤 에러가 발생할지 모르니깐)

let output = try! adultAge(of: "21") // 에러가 발생하면 런타임 에러 발생

정리 작업 지정(Specifying Cleanup Actions)

defer 구문을 사용해 현재 코드 블럭이 종료되기 직전 수행해야 할 일을 지정할 수 있다. defer 구문은 return, break 혹은 예외로 인해 강제로 벗어나는 경우에도 동작하며, 열었던 파일이나 소켓을 닫거나, 수동으로 직접 할당한 메모리를 정리하는 등의 코드를 넣는데 사용된다. (defer는 에러처리 이외에 다른 구문에도 사용할 수 있다.)

defer가 여러개가 있는 경우 가장 마지막 줄부터 실행 된다. (bottom-up 순으로 실행)

전체 코드

옵셔널을 활용한 방법(try?)와 에러 전파 차단(try!) 방법은 사용하지 않았다.

--

--