Language/Swift

[Swift] Reactive Programming Combine - Debugging

jaewpark 2024. 5. 19. 22:00

print

모든 publisher 이벤트에 대한 log 메시지를 출력합니다.

이벤트가 publisher를 통과하는지 확실하지 않을 때 사용하는 연산자입니다.

 

print에는 TextOutputStream 객체를 받는 매개변수가 있습니다.

이를 사용하여 원하는 형태의 로그를 출력할 수 있습니다.

 

class TimeLogger: TextOutputStream {
  private var previous = Date()
  private let formatter = NumberFormatter()

  init() {
    formatter.maximumFractionDigits = 5
    formatter.minimumFractionDigits = 5
  }

  func write(_ string: String) {
    let trimmed = string.trimmingCharacters(in: .whitespacesAndNewlines)
    guard !trimmed.isEmpty else { return }
    let now = Date()
    print("+\(formatter.string(for: now.timeIntervalSince(previous))!)s: \(string)")
    previous = now
  }
}

let subscription = (1...3).publisher
  .print("publisher", to: TimeLogger())
  .sink { _ in }
  
// *--- RESULT ---*
// +0.01488s: publisher: receive subscription: (1...3)
// +0.02142s: publisher: request unlimited
// +0.00013s: publisher: receive value: (1)
// +0.00009s: publisher: receive value: (2)
// +0.00007s: publisher: receive value: (3)
// +0.00007s: publisher: receive finished

 

handleEvents를 사용하면 정보 출력하는 것 외에도 stream의 다른 publisher에게 직접적인 영향을 미치지 않는 performing side effects 발생한다. publisher의 라이프사이클에서 모든 이벤트를 가로챈 다음 각 단계에서 조치를 취할 수 있습니다.

.handleEvents(receiveSubscription: { _ in
  print("Network request will start")
}, receiveOutput: { _ in
  print("Network request data received")
}, receiveCancel: {
  print("Network request cancelled")
})

 

breakpointOnError

upstream 중 하나에서 오류가 발생하면 Debugger에서 중단되어 스택을 살펴보고 publisher에서 오류가 발생한 이유와 위치를 찾을 수 있습니다. 

breakpoint

 다양한 이벤트를 가로채고 디버거를 일시 중지할 수 있는 여부를 케이스별로 결정할 수 있습니다.

클로저 내부에서 true로 반환되면 에러가 발생합니다.

  • receiveSubscription
    : publisher가 subscription을 받을 때 실행되는 클로저
  • receiveOutput
    : publisher가 값을 받을 때 실행되는 클로저
  • receiveCompletion
    : publisher가 완료를 수신하면 실행되는 클로저
var subscriptions = Set<AnyCancellable>()

let publisher = PassthroughSubject<String?, Never>()

publisher
    .breakpoint(
        receiveOutput: { value in return value == "DEBUGGER" }
    )
    .sink { print("\(String(describing: $0))" , terminator: " ") }
    .store(in: &subscriptions)

publisher.send("DEBUGGER")

 

Error 발생