DEV Community

David Goyes
David Goyes

Posted on

Combine #10: Depuración

Imprimiendo eventos

print(_:to:) es un Publisher "pasa-manos" que muestra información de lo que está pasando.

let subscription = (1...3).publisher
  .print("publisher")
  .sink { _ in }
// SALIDA
// publisher: receive subscription: (1...3)
// publisher: request unlimited
// publisher: receive value: (1)
// publisher: receive value: (2)
// publisher: receive value: (3)
// publisher: receive finished
Enter fullscreen mode Exit fullscreen mode

Este Publisher imprime lo siguiente:

  1. Una descripción del Publisher de entrada, cuando recibe una suscripción.
  2. La demanda de la suscripción.
  3. Cada elemento recibido del Publisher de entrada.
  4. El evento de fin.

print(_:to:) imprime mensajes en la consola por defecto, sin embargo, también puede recibir un TextOutputStream personalizado para loggear información en otro lugar. Por ejemplo:

fileprivate 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 }
Enter fullscreen mode Exit fullscreen mode

Disparar efectos secundarios

handleEvents(receiveSubscription:receiveOutput:receiveCompletion:receiveCancel:receiveRequest:) ejecuta cierto closure cuando ocurre algún evento de un Publisher. Se usa para agregar eventos secundarios en la mitad del pipeline, sin alterar el flujo de de datos original del mismo. Este comportamiento sirve para depurar el flujo.

request
  .handleEvents(receiveSubscription: { _
    print("Empezó la suscripción")
  }, receiveOutput: { _ in
    print("Se emitió un valor")
  }, receiveCompletion: { _ in
    print("El Publisher terminó de forma exitosa o con error"
  }, receiveCancel: {
    print("Se canceló la suscripción")
  })
  .sink( ... )
Enter fullscreen mode Exit fullscreen mode

Puntos de quiebre (breakpoints)

breakpointOnError() frena el depurador cuando algún Publisher emite una falla. breakpoint(receiveSubscription:receiveOutput:receiveCompletion:) permite interceptar cualquiera de los eventos (i.e. suscripción, emisión de valor y emisión de fin) que cumpla con un predicado. Por ejemplo:

.breakpoint(receiveOutput: { value in
  return value > 5 && value < 10
})
Enter fullscreen mode Exit fullscreen mode

Cuestionario

1. ¿Qué hace el operador print(_:to:) en un pipeline de Combine? ✅

  • [ ] Interrumpe el flujo para mostrar solo los primeros valores.
  • [ ] Imprime información sobre los eventos del Publisher, como suscripción, valores y finalización. 
  • [ ] Transforma los valores en cadenas de texto.
  • [ ] Solo imprime los errores.

2. Menciona cuatro tipos de eventos que print() puede mostrar en la consola

3. ¿El operador print() modifica los valores emitidos por el Publisher?

4. Si ejecutas este código:

let subscription = (1...3).publisher
    .print("contador")
    .sink { _ in }
Enter fullscreen mode Exit fullscreen mode

¿Qué palabra aparecerá al inicio de cada línea en la consola?

5. ¿Para qué sirve el parámetro to: en print(_:to:)? ✅

  • [ ] Para indicar el número de elementos a imprimir.
  • [ ] Para definir un TextOutputStream personalizado donde se escribirán los mensajes. 
  • [ ] Para enviar los mensajes a la consola de Xcode obligatoriamente.
  • [ ] Para redirigir la salida al operador sink.

6. En el siguiente código, ¿qué hace la clase TimeLogger?

fileprivate class TimeLogger: TextOutputStream {
  private var previous = Date()
  func write(_ string: String) {
    let now = Date()
    print("+\(now.timeIntervalSince(previous))s: \(string)")
    previous = now
  }
}
Enter fullscreen mode Exit fullscreen mode

7. ¿Para qué se usa handleEvents en Combine?

8. ¿Cuál es la diferencia entre handleEvents y print()? ✅

  • [ ] print() modifica el flujo, handleEvents no.
  • [ ] Ambos modifican los valores emitidos.
  • [ ] handleEvents permite ejecutar código personalizado en cada evento, mientras que print() solo muestra logs predeterminados. 
  • [ ] No hay diferencia.

9. ¿Cuál es la función de breakpointOnError()?

10. ¿Cuál de los siguientes operadores te permite pausar la ejecución solo si se cumple una condición sobre los valores emitidos? ✅

  • [ ] breakpointOnError()
  • [ ] breakpoint(receiveOutput:)
  • [ ] handleEvents(receiveOutput:)
  • [ ] print()

Solución

1. ¿Qué hace el operador print(_:to:) en un pipeline de Combine?

  • [✅] Imprime información sobre los eventos del Publisher, como suscripción, valores y finalización.

2. Menciona cuatro tipos de eventos que print() puede mostrar en la consola

Suscripción, demanda, valores recibidos y fin (cancelación).

3. ¿El operador print() modifica los valores emitidos por el Publisher?

No. Solo muestra en consola

4. Si ejecutas este código:

let subscription = (1...3).publisher
    .print("contador")
    .sink { _ in }
Enter fullscreen mode Exit fullscreen mode

¿Qué palabra aparecerá al inicio de cada línea en la consola?

Contador

5. ¿Para qué sirve el parámetro to: en print(_:to:)

  • [✅] Para definir un TextOutputStream personalizado donde se escribirán los mensajes.

6. En el siguiente código, ¿qué hace la clase TimeLogger?

fileprivate class TimeLogger: TextOutputStream {
  private var previous = Date()
  func write(_ string: String) {
    let now = Date()
    print("+\(now.timeIntervalSince(previous))s: \(string)")
    previous = now
  }
}
Enter fullscreen mode Exit fullscreen mode

Imprime la diferencia en tiempos entre dos eventos publicados.

7. ¿Para qué se usa handleEvents en Combine?

Para agregar eventos secundarios en la mitad del flujo (sin alterar los datos para el resto de la cadena).

8. ¿Cuál es la diferencia entre handleEvents y print()

  • [✅] handleEvents permite ejecutar código personalizado en cada evento, mientras que print() solo muestra logs predeterminados.

9. ¿Cuál es la función de breakpointOnError()?

Detiene la ejecución cuando algún Publisher emite un error.

10. ¿Cuál de los siguientes operadores te permite pausar la ejecución solo si se cumple una condición sobre los valores emitidos? 

  • [✅] breakpoint(receiveOutput:)

Top comments (0)