paint-brush
Editores úteis em Swift: um guia essencialpor@vadimchistiakov
1,286 leituras
1,286 leituras

Editores úteis em Swift: um guia essencial

por Vadim Chistiakov11m2023/01/18
Read on Terminal Reader

Muito longo; Para ler

Um editor é um tipo que está em conformidade com o protocolo `Publisher`. É responsável por fornecer um fluxo de valores aos assinantes. Um editor pode emitir um ou mais valores ao longo do tempo e também pode concluir ou falhar. A estrutura Combine fornece vários editores integrados.
featured image - Editores úteis em Swift: um guia essencial
Vadim Chistiakov HackerNoon profile picture
0-item

Visão geral

Na estrutura Combine, um publicador é um tipo que está em conformidade com o protocolo do Publisher . É responsável por fornecer um fluxo de valores aos assinantes. O protocolo Publisher define dois tipos associados: Output e Failure , que indicam os tipos de valores que o editor pode emitir e os tipos de erros que pode lançar, respectivamente.


Um editor pode emitir um ou mais valores ao longo do tempo e também pode concluir ou falhar. Quando um assinante assina um editor, o editor chama o método receive(subscription:) do assinante e passa a ele um objeto Subscription , que o assinante pode usar para controlar o fluxo de valores. O assinante também pode chamar o método receive(_:) no publicador para receber novos valores.


A estrutura Combine fornece vários editores integrados, como Just , Fail , Empty , Deferred e Sequence , que podem ser usados para criar vários tipos de editores. Além disso, você pode criar seus próprios editores personalizados em conformidade com o protocolo Publisher e implementando os métodos necessários.


Os editores também podem ser compostos juntos para criar pipelines mais complexos. A estrutura Combine fornece vários operadores integrados que podem ser usados para modificar e combinar editores, como map , filter , reduce , flatMap , zip e merge . Esses operadores são fornecidos pela extensão do protocolo Publisher e podem ser chamados em qualquer editor.


Agora eu gostaria de oferecer a vocês alguns editores úteis que eu uso em meus projetos.

Editor de cronômetro repetitivo

Para implementar um editor que usa um cronômetro de repetição com um intervalo personalizado no Swift, você pode usar a classe Timer da estrutura Foundation. Aqui está um exemplo de como você pode fazer isso:


RepeatingTimeSubscription está em conformidade com o 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 está em conformidade com o protocolo do 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 usar este editor, você pode criar uma instância dele e assiná-lo usando o método sink do protocolo Publisher .


Por exemplo:

 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)


Isso imprimirá "Temporizador disparado!" a cada 5 segundos. Você pode cancelar a assinatura chamando o método cancel no objeto AnyCancellable que é retornado pelo método sink .


Por exemplo:


 deinit { cancellable?.cancel() }


Publicador de sondagem longa

Para implementar a sondagem longa usando a estrutura Combine no Swift, você pode criar um editor que faça uma solicitação de rede em um intervalo especificado e retorne a resposta como saída. Aqui está um exemplo de como você pode fazer isso:


Enumeração de erro personalizada para casos com falha.

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


LongPollingSubscription está em conformidade com o 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 está em conformidade com o protocolo do 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 você pode usar qualquer tipo genérico de resposta que esteja em conformidade com o protocolo Decodable .


Para testar, você precisa criar um modelo que esteja em conformidade Decodable . Eu uso uma API pública por https://pixabay.com/api .


Que seja a estrutura PhotoResponse:


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


Para usar este editor, você pode criar uma instância dele e assiná-lo usando o método sink do protocolo Publisher . Por exemplo:


 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()


Mais uma coisa

Há vários editores personalizados úteis que podem ser criados usando a estrutura Combine no Swift. Aqui estão alguns exemplos:

  1. NotificationCenterPublisher : Um publicador que emite valores quando uma notificação especificada é postada no NotificationCenter . Você pode usar este editor para reagir a eventos específicos do sistema ou do aplicativo, como uma rotação de dispositivo ou uma alteração de status da rede.
  2. KeyboardPublisher : Um editor que emite valores quando o teclado é mostrado ou oculto. Você pode usar este editor para ajustar o layout de suas exibições quando o teclado é apresentado ou dispensado.
  3. CoreLocationPublisher : um publicador que emite valores quando a localização do usuário é alterada. Este editor pode ser usado para rastrear a localização do usuário e executar ações com base em sua localização.
  4. UIControlEventPublisher : um publicador que emite valores quando um evento especificado ocorre em um UIControl , como UIButton ou UITextField. Isso pode ser usado para lidar com as interações do usuário de maneira reativa.

Esses são apenas alguns exemplos dos tipos de editores personalizados que podem ser criados usando a estrutura Combine. A chave é entender os requisitos de seu aplicativo e usar os blocos de construção disponíveis fornecidos pela estrutura para criar editores que atendam a esses requisitos.

Para concluir

Por fim, é importante observar que o framework Combine usa o paradigma de programação reativa funcional, que é um modelo de programação que lida com fluxos de eventos ao longo do tempo. Os editores, juntamente com os assinantes e operadores, são os principais blocos de construção desse paradigma e facilitam a criação de aplicativos complexos e responsivos.