관리 메뉴

J

[Combine] 에러 처리: tryMap, catch, replaceError 본문

iOS/Combine

[Combine] 에러 처리: tryMap, catch, replaceError

yujaehui 2025. 4. 8. 23:35

Combine에서의 에러 처리: tryMap, catch, replaceError

Combine을 사용하다 보면 네트워크 요청, JSON 파싱, 사용자 입력 등 다양한 상황에서 에러가 발생할 수 있습니다.

Combine에서는 스트림 중간에 에러가 발생하면 스트림이 종료되므로, 이를 적절히 처리할 수 있는 에러 핸들링 기법이 중요합니다.


1. 에러가 있는 Publisher vs 없는 Publisher

Combine에서는 Publisher가 에러를 발생시킬 수 있는지 여부에 따라 타입이 다릅니다.

// 에러를 발생시키지 않는 Publisher
let noErrorPublisher = Just("Hello") // 타입: Just<String>

// 에러를 발생시킬 수 있는 Publisher
let errorPublisher = Fail<String, URLError>(error: URLError(.badURL))
  • Publisher의 제네릭 형식은 <Output, Failure> 형태
  • Failure 타입이 Never이면 에러가 발생하지 않음
  • 에러가 발생할 수 있으면, Failure가 Error 또는 그 하위 타입

2. tryMap – 에러를 던질 수 있는 변환 처리

map은 단순한 변환만 가능하지만, tryMap은 변환 도중 에러를 throw할 수 있는 로직을 포함할 수 있습니다.

let values = ["1", "2", "Three", "4"]

values.publisher
    .tryMap { str -> Int in
        guard let intVal = Int(str) else {
            throw NSError(domain: "InvalidNumber", code: -1)
        }
        return intVal
    }
    .sink(
        receiveCompletion: { completion in
            switch completion {
            case .failure(let error):
                print("에러 발생: \(error)")
            case .finished:
                print("완료")
            }
        },
        receiveValue: { value in
            print("값: \(value)")
        }
    )

 

값: 1
값: 2
에러 발생: Error Domain=InvalidNumber Code=-1 ...
  • tryMap 안에서 에러가 발생하면 스트림이 즉시 종료

3. catch – 에러를 감지하고 다른 Publisher로 대체

catch는 에러가 발생했을 때, 다른 Publisher로 스트림을 이어가도록 만들어줍니다.

let publisher = Fail<String, Error>(error: NSError(domain: "Error", code: -1))

publisher
    .catch { error in
        Just("기본값으로 대체") // 새 Publisher 반환
    }
    .sink { value in
        print("결과: \(value)")
    }

 

결과: 기본값으로 대체
  • 에러가 발생해도 스트림이 완료되지 않고 계속 진행 가능
  • 실무에서 네트워크 실패 시 대체 로직에 자주 사용됨

4. replaceError – 에러를 특정 값으로 대체하고 종료

replaceError(with:)는 에러 발생 시 특정 값을 리턴하고 스트림을 종료합니다.

catch보다 간단한 대안입니다.

let publisher = Fail<String, Error>(error: NSError(domain: "Fail", code: -1))

publisher
    .replaceError(with: "에러 발생 → 기본값 사용")
    .sink { value in
        print("출력: \(value)")
    }

 

출력: 에러 발생 → 기본값 사용
  • 단순히 에러를 무시하고 기본 값으로 대체 후 종료

언제 어떤 걸 써야 할까?

목적 사용 연산자
에러를 던지는 변환 처리 tryMap
에러 발생 시 새로운 스트림으로 전환 catch
에러 발생 시 값 하나로 대체 후 종료 replaceError

정리

연산자 기능
tryMap 변환 중 에러 발생 가능
catch 에러 발생 시 다른 Publisher로 대체
replaceError(with:) 에러 발생 시 특정 값으로 대체 후 스트림 종료

 

Combine에서는 에러가 발생하면 기본적으로 스트림이 멈추기 때문에, 상황에 맞는 에러 처리 로직을 꼭 작성해두는 것이 중요합니다.