-
Swift 6 : Typed Throws ( 에러도 타입을 줘서 더 명확히 처리하자.)Apple🍎/Swift 2025. 4. 14. 16:52
Swift 6의 Typed Throws: 오류 처리의 새로운 패러다임
Swift 6에서 도입된 "typed throws"는 Swift의 오류 처리 시스템에 중요한 발전을 가져왔습니다. 이 기능을 통해 함수가 발생시킬 수 있는 구체적인 오류 유형을 명시적으로 선언할 수 있게 되었습니다.
Swift의 기존 오류 처리 방식
Swift 5까지는 함수가 오류를 던질 수 있다는 것만 표시할 수 있었고, 어떤 종류의 오류를 던질 수 있는지는 명시할 수 없었습니다:
enum DatabaseError: Error { case connectionFailed case queryFailed } enum NetworkError: Error { case timeout case serverDown } // 이 함수는 어떤 오류든 던질 수 있음을 나타내지만, 구체적으로 어떤 오류인지는 명시하지 않습니다 func fetchUserData() throws -> UserData { // 구현... }
이 접근 방식의 한계는 호출하는 쪽에서 이 함수가 어떤 종류의 오류를 발생시킬 수 있는지 알 수 없다는 것입니다. 문서나 코드를 살펴봐야만 알 수 있었습니다.
Swift 6의 Typed Throws 소개
Swift 6에서는 함수가 던질 수 있는 오류 유형을 명시적으로 선언할 수 있게 되었습니다.
// 이 함수는 DatabaseError만 던질 수 있음을 명시합니다 func fetchUserData() throws(DatabaseError) -> UserData { // 구현... } // 이 함수는 DatabaseError와 NetworkError를 던질 수 있음을 명시합니다 func syncData() throws(DatabaseError, NetworkError) -> Bool { // 구현... }
Typed Throws의 장점
- 명확한 계약: 함수 시그니처를 통해 함수가 던질 수 있는 오류 유형이 명확하게 드러납니다.
- 컴파일 타임 검사: 컴파일러가 함수가 선언되지 않은 오류 유형을 던지는 것을 방지할 수 있습니다.
- 더 정확한 오류 처리: 호출하는 쪽에서 처리해야 할 오류 유형을 정확히 알 수 있습니다.
- 코드 문서화: 코드 자체가 어떤 오류가 발생할 수 있는지 문서화합니다.
실제 사용 예시
실제 코드에서 typed throws를 어떻게 사용하고 처리하는지 살펴보겠습니다.
enum DatabaseError: Error { case connectionFailed case queryFailed case insufficientPermissions } enum ValidationError: Error { case invalidInput case missingField(String) } // 함수 선언 - 특정 오류 유형만 던짐 func saveUser(_ user: User) throws(DatabaseError, ValidationError) -> Bool { guard user.isValid() else { throw ValidationError.invalidInput } guard user.name.count > 0 else { throw ValidationError.missingField("name") } if !database.isConnected { throw DatabaseError.connectionFailed } // 데이터 저장 로직... return true } // 호출 측에서의 오류 처리 func createNewUser() { do { let success = try saveUser(newUser) print("User saved successfully") } catch let error as DatabaseError { switch error { case .connectionFailed: print("Could not connect to database") case .queryFailed: print("Database query failed") case .insufficientPermissions: print("Not enough permissions to save user") } } catch let error as ValidationError { switch error { case .invalidInput: print("User data is invalid") case .missingField(let fieldName): print("Required field missing: \(fieldName)") } } catch { // 이 부분은 실행되지 않을 것입니다. 왜냐하면 saveUser 함수는 // DatabaseError와 ValidationError만 던지기 때문입니다. print("Unknown error: \(error)") } }
기존 throws와의 호환성
Swift 6는 기존 코드와의 호환성을 유지하기 위해 일반적인 throws도 계속 지원합니다. 이는 모든 가능한 오류를 던질 수 있음을 의미합니다:
// 여전히 유효한 코드입니다 - 어떤 Error든 던질 수 있음 func legacyFunction() throws -> String { // 구현... }
함수 합성과 오류 전파
Typed throws는 함수 합성과 오류 전파에서도 이점을 제공합니다.
func processUserData() throws(DatabaseError, ValidationError, NetworkError) -> ProcessedData { // saveUser는 DatabaseError와 ValidationError만 던질 수 있습니다 let saved = try saveUser(user) // fetchAdditionalData는 NetworkError만 던질 수 있습니다 let additionalData = try fetchAdditionalData(user.id) // 이 함수는 세 가지 오류 유형을 모두 전파할 수 있습니다 return ProcessedData(saved: saved, additional: additionalData) }
서브타이핑과 다형성
Typed throws는 서브타이핑 규칙을 따릅니다. 부모 클래스에서 특정 오류를 던지는 메서드를 선언하면, 자식 클래스는 같은 오류나 그 하위 집합만 던질 수 있습니다.
class DataService { func fetchData() throws(NetworkError, DatabaseError) -> Data { // 구현... } } class CachedDataService: DataService { // 유효함: 부모보다 적은 오류 유형을 던짐 override func fetchData() throws(NetworkError) -> Data { // 구현... } } class InvalidService: DataService { // 컴파일 오류: 부모가 선언하지 않은 추가 오류 유형을 던질 수 없음 override func fetchData() throws(NetworkError, DatabaseError, ValidationError) -> Data { // 구현... } }
제네릭과의 상호 작용
Typed throws는 제네릭 프로그래밍과도 잘 통합됩니다.
// E는 Error 프로토콜을 준수하는 어떤 타입이든 될 수 있습니다 func processGeneric<T, E: Error>(value: T) throws(E) -> T { // 구현... } // 여러 제네릭 오류 타입을 사용할 수도 있습니다 func complexOperation<E1: Error, E2: Error>(data: Data) throws(E1, E2) -> Result { // 구현... }
정리
Swift 6의 typed throws는 코드의 안전성과 명확성을 크게 향상시키는 기능입니다. 이 기능을 통해 프로그래머는 함수가 발생시킬 수 있는 오류 유형을 명시적으로 문서화할 수 있으며, 컴파일러는 이를 기반으로 더 엄격한 검사를 수행할 수 있습니다. 이는 더 견고하고 유지보수가 용이한 코드를 작성하는 데 도움이 되며, 런타임에 발견될 오류를 컴파일 타임에 잡아낼 수 있게 해줍니다.
'Apple🍎 > Swift' 카테고리의 다른 글
DispatchQueue와 DispatchWorkItem 비교하기 (0) 2025.04.17 Swift에서의 데이터 레이스 방지를 위한 동기화 기법 (0) 2025.04.16 inout 파라미터 작동 방식 파해치기 (0) 2025.03.11 Swift의 컬렉션 타입 : 값 의미론과 실제 구현 (0) 2025.02.28 클로저 종결판 2 (0) 2025.02.26