Swift 5 : 에러 핸들링

버들비·2020년 7월 16일
0

Swift

목록 보기
10/10

스위프트에는 에러를 처리하는데 두가지 단계가 있다. 첫번째는 iOS 앱의 메소드 내에서 원하는 결과가 나오지 않을 경우 에러를 발생(스로잉)시키는 것이고, 두번째는 메소드가 던진 에러를 잡아서 처리하는 것이다.
에러 타입은 Error 프로토콜을 따르는 모든 값이 될 수 있다.

에러 타입 선언하기

예를 들어 원격 서버에 파일을 전송하는 메소드가 있다고 하자. 네트워크 연결이 없거나, 네트워크 속도가 너무 느리거나, 전송할 파일을 찾지 못한다거나 하는 에러는 다음과 같이 Error 프로토콜을 따르는 열거형으로 표현할 수 있다.

enum FileTrasferError: Error {
	case noConnection
    case lowBandwidth
    case fileNotFound
}

guard 구문을 이용한 에러 쓰로잉

에러를 던지는데는 throws 키워드를 사용한다. (throw 가 아니라 throws 다!)
결과를 반환하는 메소드나 함수의 경우, throws 키워드는 반환 타입 앞에 위치하게 된다.

func transferFile() throws -> Bool {
	// 
}

에러를 던지는 로직은 throws 구문의 throw 와 guard 구문을 이용한다.

var connection = true
var connectionSpeed = 30.00
var fileFound = false

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

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

guard 구문의 조건문이 false 경우에는 else 절에 해당하는 에러 쓰로잉이 발생한다.

에러를 던지는 함수 호출하기

메소드 또는 함수에 에러를 던지는 로직이 포함돼 있다면, 함수를 호출할때 일반적인 방법으로 호출할 수 없다. 이런 함수는 호출할 때 try 구문을 앞에 붙여야 한다.

try fileTransfer()

에러 핸들링 함수는 do-catch 구문과 함께 사용된다. 예제 코드는 다음과 같다.

func checkSendingFile() -> String {
	do {
    	try fileTransfer()
 	} catch FileTransferError.noConnection {
    	return "No Network Connection"
    } catch FileTransferError.lowBandwidth {
    	return "File Transfer Speed is Too Low"
    } catch FileTransferError.fileNotFound {
    	return "File Not Found"
    } catch {
    	return "Unknown Error"
    }
    return "Transfer Success"
}

파일전송을 체크하는 함수이다. do 내에서 fileTransfer() 함수가 에러를 던질경우, catch 구문이 각 에러에 해당되는 문자열을 반환하게 돼 있다. 아무런 에러가 없을 경우 전송 성공 문자열을 반환한다.
마지막 catch 는 'catch all' 구문으로, 패턴매칭이 이뤄지지 않은 모든 에러에 대해 "Unknown Error" 를 반환하게 한다. do-catch 구문은 가능한 모든 에러에 대해 처리할 수 있도록 구성돼야 하기에, 이런 로직이 필요하다.

defer 구문의 사용

앞서 살펴본 checkSendingFile() 파일 함수는 에러 발생시 해당되는 문자열을 반환하고 제어권을 반환하지만, 제어권을 반환하기 전에 추가적인 작업을 하는게 효율적일 때가 있다.
파일전송의 경우 제어권을 반환하기 전에 임시 파일들을 지워야 하는 경우가 있다. 이런 작업은 defer 구문을 이용한다. defer 구문은 함수가 결과를 반환하기 직전에 실행되어야 하는 코드를 지정할 수 있게 해준다.

func checkSendingFile() -> String {
	
    defer {
    	removeTemporalFiles()
        closeConnection()
    }
    
	do {
    	try fileTransfer()
 	} catch FileTransferError.noConnection {
    	return "No Network Connection"
    } catch FileTransferError.lowBandwidth {
    	return "File Transfer Speed is Too Low"
    } catch FileTransferError.fileNotFound {
    	return "File Not Found"
    } catch {
    	return "Unknown Error"
    }
    return "Transfer Success"
}

이제 checkSendingFile() 함수는 제어권을 반환하기 전에 removeTemporalFiles() 함수와 closeConnection 함수가 항상 호출된다.

0개의 댓글