paint-brush
Editores útiles en Swift: una guía esencialpor@vadimchistiakov
1,389 lecturas
1,389 lecturas

Editores útiles en Swift: una guía esencial

por Vadim Chistiakov11m2023/01/18
Read on Terminal Reader

Demasiado Largo; Para Leer

Un editor es un tipo que se ajusta al protocolo `Publisher`. Es responsable de proporcionar un flujo de valores a los suscriptores. Un publicador puede emitir uno o más valores a lo largo del tiempo y también puede completarse o fallar. El marco Combine proporciona una serie de editores integrados.
featured image - Editores útiles en Swift: una guía esencial
Vadim Chistiakov HackerNoon profile picture
0-item

Descripción general

En el marco Combine, un publicador es un tipo que se ajusta al protocolo de Publisher . Es responsable de proporcionar un flujo de valores a los suscriptores. El protocolo Publisher define dos tipos asociados: Output y Failure , que indican los tipos de los valores que puede emitir el publisher y los tipos de errores que puede arrojar, respectivamente.


Un publicador puede emitir uno o más valores a lo largo del tiempo y también puede completarse o fallar. Cuando un suscriptor se suscribe a un editor, el editor llama al método receive(subscription:) del suscriptor y le pasa un objeto Subscription , que el suscriptor puede usar para controlar el flujo de valores. El suscriptor también puede llamar al método receive(_:) en el publicador para recibir nuevos valores.


El marco Combine proporciona una serie de publicadores integrados, como Just , Fail , Empty , Deferred y Sequence , que se pueden usar para crear varios tipos de publicadores. Además, puede crear sus propios publicadores personalizados conforme al protocolo de Publisher e implementando los métodos requeridos.


Los editores también se pueden componer juntos para crear canalizaciones más complejas. El marco Combine proporciona una serie de operadores integrados que se pueden usar para modificar y combinar editores, como map , filter , reduce , flatMap , zip y merge . Estos operadores los proporciona la extensión del protocolo Publisher y se pueden llamar en cualquier editor.


Ahora me gustaría ofrecerle algunos editores útiles que utilizo en mis proyectos.

Editor de temporizador de repetición

Para implementar un editor que usa un temporizador repetitivo con un intervalo personalizado en Swift, puede usar la clase Timer del marco Foundation. Aquí tienes un ejemplo de cómo puedes hacerlo:


RepeatingTimeSubscription cumple con el protocolo de Subscription :


 private class RepeatingTimerSubscription<S: Subscriber>: Subscription where S.Input == Void { private let interval: TimeInterval private let queue: DispatchQueue private var subscriber: S? private var timer: Timer? init(interval: TimeInterval, queue: DispatchQueue, subscriber: S) { self.interval = interval self.queue = queue self.subscriber = subscriber } func request(_ demand: Subscribers.Demand) { timer?.invalidate() timer = Timer.scheduledTimer( withTimeInterval: interval, repeats: true ) { [weak self] _ in self?.queue.async { _ = self?.subscriber?.receive() } } } func cancel() { timer?.invalidate() timer = nil subscriber = nil } }


RepeatingTimePublisher cumple con el protocolo de Publisher :


 import Foundation import Combine final class RepeatingTimerPublisher: Publisher { typealias Output = Void typealias Failure = Never private let interval: TimeInterval private let queue: DispatchQueue init(interval: TimeInterval, queue: DispatchQueue = .main) { self.interval = interval self.queue = queue } func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input { let subscription = RepeatingTimerSubscription( interval: interval, queue: queue, subscriber: subscriber ) subscriber.receive(subscription: subscription) } }



Para utilizar este publicador, puede crear una instancia del mismo y suscribirse mediante el método sink del protocolo del Publisher .


Por ejemplo:

 private var cancellable: AnyCancellable? func subscribeOnTimer(interval: TimeInterval) { let publisher = RepeatingTimerPublisher(interval: interval) cancellable = publisher.sink { print("Timer fired!") } } //TEST THE METHOD subscribeOnTimer(interval: 5.0)


Esto imprimirá "¡Temporizador disparado!" cada 5 segundos. Puede cancelar la suscripción llamando al método de cancel en el objeto AnyCancellable que devuelve el método sink .


Por ejemplo:


 deinit { cancellable?.cancel() }


Publicador de sondeo largo

Para implementar un sondeo largo utilizando el marco Combine en Swift, puede crear un editor que realice una solicitud de red en un intervalo específico y devuelva la respuesta como salida. Aquí tienes un ejemplo de cómo puedes hacerlo:


Enumeración de error personalizada para casos fallidos.

 enum CustomError: Error { case invalidResponse case invalidDecoding case error }


LongPollingSubscription cumple con el protocolo de Subscription :


 private class LongPollingSubscription<S: Subscriber, Output: Decodable>: Subscription where S.Input == Output, S.Failure == CustomError { private let url: URL private let interval: TimeInterval private let decoder: JSONDecoder private var subscriber: S? private var timer: Timer? private var task: URLSessionDataTask? init( url: URL, interval: TimeInterval, subscriber: S, decoder: JSONDecoder = JSONDecoder() ) { self.url = url self.interval = interval self.subscriber = subscriber self.decoder = decoder } func request(_ demand: Subscribers.Demand) { timer?.invalidate() timer = Timer.scheduledTimer( withTimeInterval: interval, repeats: true ) { [weak self] _ in self?.makeRequest() } makeRequest() } func cancel() { timer?.invalidate() timer = nil task?.cancel() task = nil subscriber = nil } private func makeRequest() { task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let self else { return } if let error = error as? S.Failure { self.subscriber?.receive( completion: .failure(error) ) return } guard let data else { self.subscriber?.receive( completion: .failure(.invalidResponse) ) return } do { let output = try self.decoder.decode( Output.self, from: data ) _ = self.subscriber?.receive(output) } catch { self.subscriber?.receive( completion: .failure(.invalidDecoding) ) } } task?.resume() } }


LongPollingPublisher cumple con el protocolo de Publisher :


 final class LongPollingPublisher<Output: Decodable>: Publisher { typealias Failure = CustomError private let url: URL private let interval: TimeInterval init(url: URL, interval: TimeInterval) { self.url = url self.interval = interval } func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input { let subscription = LongPollingSubscription( url: url, interval: interval, subscriber: subscriber ) subscriber.receive(subscription: subscription) } }


<Output: Decodable> significa que puede usar cualquier tipo genérico de respuesta que se ajuste al protocolo Decodable .


Para las pruebas, debe crear un modelo que se ajuste a Decodable . Uso una API pública de https://pixabay.com/api .


Que sea la estructura PhotoResponse:


 struct PhotoResponse: Decodable { struct Photo: Decodable { let user: String let id: Int let largeImageURL: String } let hits: [Photo] let total: Int }


Para utilizar este publicador, puede crear una instancia del mismo y suscribirse mediante el método sink del protocolo del Publisher . Por ejemplo:


 private var cancellable: AnyCancellable? private func pollingTest() { let url = URL(string: "https://pixabay.com/api/?key={your_key}")! let publisher = LongPollingPublisher<PhotoResponse>( url: url, interval: 5.0 ) cancellable = publisher.sink(receiveCompletion: { completion in switch completion { case .finished: print("Completed") case .failure(let error): print("Error: \(error)") } }, receiveValue: { response in print("Received response: \(response)") }) } //TEST THE METHOD pollingTest()


Una cosa más

Hay una serie de editores personalizados útiles que se pueden crear utilizando el marco Combine en Swift. Aquí están algunos ejemplos:

  1. NotificationCenterPublisher : un publicador que emite valores cuando una notificación específica se publica en el NotificationCenter . Puede usar este publicador para reaccionar ante eventos específicos del sistema o de la aplicación, como la rotación de un dispositivo o un cambio de estado de la red.
  2. KeyboardPublisher : un editor que emite valores cuando el teclado se muestra u oculta. Puede usar este editor para ajustar el diseño de sus vistas cuando se presenta o descarta el teclado.
  3. CoreLocationPublisher : un editor que emite valores cuando cambia la ubicación del usuario. Este editor se puede utilizar para rastrear la ubicación del usuario y realizar acciones en función de su ubicación.
  4. UIControlEventPublisher : un editor que emite valores cuando ocurre un evento específico en un UIControl como UIButton o UITextField. Esto se puede utilizar para manejar las interacciones del usuario de forma reactiva.

Estos son solo algunos ejemplos de los tipos de editores personalizados que se pueden crear utilizando el marco Combine. La clave es comprender los requisitos de su aplicación y utilizar los componentes básicos disponibles proporcionados por el marco para crear editores que cumplan con esos requisitos.

En conclusión

Finalmente, es importante tener en cuenta que el marco Combine utiliza el paradigma de programación reactiva funcional, que es un modelo de programación que trata con flujos de eventos a lo largo del tiempo. Los editores, junto con los suscriptores y los operadores, son los componentes básicos de este paradigma y facilitan la creación de aplicaciones complejas y receptivas.