스위프트는 Error 프로토콜과 throw, try, catch 구문을 통해 엄격한 오류 처리 시스템을 지원합니다. 사용자가 정의한 오류 유형을 Error에서 상속받아 만들 수 있습니다:
enum NetworkError: Error { case noInternet case serverError(code: Int) case unknown }
오류를 던질 수 있는 함수는 throws로 선언됩니다:
func fetchData() throws -> Data { // ... throw NetworkError.noInternet }
오류는 do-catch 블록을 사용해 처리할 수 있습니다:
do { let data = try fetchData() // 데이터 작업 } catch NetworkError.noInternet { print("인터넷 없음") } catch { print("다른 오류: \(error)") }
대체 접근법은 Result<T, Error> 유형을 사용하여 try-catch 없이 결과 또는 오류를 반환할 수 있습니다:
func fetchData() -> Result<Data, NetworkError> { // ... return .failure(.noInternet) } let result = fetchData() switch result { case .success(let data): // OK case .failure(let err): // 오류 처리 }
언제 사용해야 할까요:
try/catch를 사용하세요.Result를 사용하세요.질문: "문자열이나 숫자와 같은 모든 유형의 오류를 던지고 잡을 수 있습니까?"
답변: 아니요, 스위프트에서는 Error 프로토콜에 해당하는 유형만 던질 수 있습니다.
// 잘못된 예: throw "StringError" // 컴파일러가 이를 허용하지 않음 // 올바른 예: struct MyError: Error {} throw MyError()
이야기
REST API 클라이언트 프로젝트에서 문자열로 오류를 던졌습니다 (throw "No data"). JavaScript에서는 컴파일되었지만, 스위프트로 변환한 후 치명적인 컴파일 오류가 발생했습니다.
이야기
개발자가 오류를 옵셔널 값으로 반환했습니다 (오류 시 return nil), throw/Result를 사용하지 않았습니다. 그 결과, 오류 세부정보가 손실되어 정확하게 처리하기 어려웠고, Silent fails가 발생했습니다.
이야기
분석 결과 응용 프로그램의 여러 곳에서 동일한 오류가 하나의 Error 유형으로 그룹화되지 않았습니다. 그 결과 응용 프로그램이 동일한 실패를 다르게 처리했고, UI는 동일한 오류에 대해 다른 메시지를 표시했습니다 — 유지 관리와 테스트가 어려웠습니다.