본문 바로가기
TIL(Today I Learned)

2025.01.24 Today I Learned

by 승환파크 2025. 1. 24.

Swift의 Result 타입

Swift의 Result타입은 에러 처리를 간소화하고 가독성을 높이기 위해서 사용하는 타입으로 주로 에러가 발생할 가능성이 있는 작업을 처리할 때 기존의 do-catch 보다 명시적이고 깔끔하게 사용할 수 있다.

 

1. Result 타입

Result는 성공과 실패를 모두 표현할 수 있는 열거형 타입이다. 

enum Result<Success, Failure> where Failure : Error {
    case success(Success)
    case failure(Failure)
}

 

Result 타입을 살펴보면 enum 으로 이루어져 있고, Success와 Failure 는 모두 제네릭 타입으로 선언되어 있는것을 확인할 수 있다. 따라서 Success 에는 어떠한 타입이든 들어갈 수 있고, Failure 에는 Error 프로토콜을 준수하는 어떠한 타입이든 들어갈 수 있다는 뜻이다.

 

2. Result 타입 사용법

우선 Result 타입을 사용하지 않은 예제 코드를 보면 아래와 같다.

func fetchUserWithoutResult(from id: Int) throws -> User {
    let database = [
        1: "Alice",
        2: "Bob",
        3: "Charlie"
    ]

    guard let name = database[id] else {
        throw DataError.notFound
    }

    if name.isEmpty {
        throw DataError.corruptedData
    }

    return User(id: id, name: name)
}

 do {
    let user = try fetchUserWithoutResult(from: 2)
    print("사용자 정보: \(user)")
} catch let error as DataError {
    switch error {
    case .notFound:
        print("에러: 사용자 정보를 찾을 수 없습니다.")
    case .corruptedData:
        print("에러: 사용자 데이터가 손상되었습니다.")
    case .unknown(let underlyingError):
        print("알 수 없는 에러 발생: \(underlyingError.localizedDescription)")
    }
} catch {
    print("알 수 없는 에러 발생: \(error)")
}

 

그리고 이번에는 Result 타입을 적용한 예제 코드이다.

struct User {
    let id: Int
    let name: String
}

enum DataError: Error {
    case notFound
    case corruptedData
    case unknown(Error)
}

func fetchUser(from id: Int) -> Result<User, DataError> {
    let database = [
        1: "Alice",
        2: "Bob",
        3: "Charlie"
    ]

    guard let name = database[id] else {
        return .failure(.notFound)
    }

    if name.isEmpty {
        return .failure(.corruptedData)
    }

    return .success(User(id: id, name: name))
}

let result = fetchUser(from: 2)
switch result {
case .success(let user):
    print("사용자 정보: \(user)")
case .failure(let error):
    switch error {
    case .notFound:
        print("에러: 사용자 정보를 찾을 수 없습니다.")
    case .corruptedData:
        print("에러: 사용자 데이터가 손상되었습니다.")
    case .unknown(let underlyingError):
        print("알 수 없는 에러 발생: \(underlyingError.localizedDescription)")
    }
}

 

이 두 코드를 보았을 때 do-catch 코드 보다 Result 코드는 성공과 실패를 명확히 구분해주기 때문에 가독성을 생각해봤을 때 조금더 직관적으로 코드의 흐름을 파악할 수 있다. 또한 위 코드에서는 다루지 않았지만 비동기 코드를 작성하는 경우 Result 타입을 사용하면 비동기 작업의 콜백에서 에러를 좀더 깔끔하게 처리하여 사용할 수 있다는 장점이 존재한다. 그리고 map, flatMap 같이 다양한 메서드들도 존재하기 때문에 데이터를 처리하기에 조금더 편리하다는 장점이 존재해서 이 Result 타입을 많이 쓰는 것 같다.

'TIL(Today I Learned)' 카테고리의 다른 글

2025.02.14 Today I Learned  (0) 2025.02.14
2025.02.05 Today I Learned  (0) 2025.02.05
2025.01.16 Today I Learned  (1) 2025.01.16
2025.01.13 Today I Learned  (0) 2025.01.13
2025.01.07 Today I Learned  (0) 2025.01.07