Guardando la lógica de filtrado en Swift Combine. Parte 2

Combinación orientada a datos





La traducción del artículo fue preparada especialmente para estudiantes del curso avanzado "Desarrollador iOS" .





En el episodio anterior, modelamos con éxito una secuencia de valores, donde se adjuntó un operador simple ( delay) a cada valor .

En esta parte, veremos algunos operadores más, los crearemos Codeabley , finalmente, los convertiremos a Combine publisher en tiempo de ejecución.



Tipos de operador


Antes de comenzar a modelarlos, debemos comprender qué tipos de operadores existen.

El sitio ReactiveX los divide en aproximadamente 10 categorías: operadores de conversión de creación, transformación, filtrado, combinación, manejo de errores, auxiliar, condicional, matemático / agregado, contrapresión, conectable-observable y observable (To). Si está interesado, ReactiveX tiene una buena explicación para cada tipo y operador.
Nota: Si no está familiarizado con RxSwift, Observable en RxSwift es equivalente a Publisher in Combine.
En la parte anterior, mencionamos el operador delay, que se refiere al utilitytipo auxiliar ( ). Hoy nos centraremos en preservar dos filteringoperadores de filtrado ( ).



Operadores de filtro


Este tipo de operador evita que todos o algunos (o ninguno) de los elementos de flujo se muevan más arriba en función de esta condición.

dropFirst


dropFirstdetiene la transmisión de los primeros nelementos. Simplemente podemos agregarlo a nuestra enumeración Operator, dada su simplicidad.

enum Operator {
 case delay(seconds: Double)
 case dropFirst(count: Int)
}

También podemos convertir fácilmente este caso de listado a Publisher.

extension Operator {func applyPublisher<T>(_ publisher: AnyPublisher<T, Never>) -> AnyPublisher<T, Never> { 
switch self {
   case .dropFirst(let count):
       return publisher.dropFirst(count).eraseToAnyPublisher()
 //   
 }}}

Ahora el operador dropFirstse puede guardar y mostrar en la lista de operadores.



El ahorro dropFirstes similar a un operador delay. Quizás el filtrado no sea tan diferente de los operadores auxiliares. Bueno, intentemos otra declaración antes de llegar a tal conclusión.

Filtrar


Por el contrario dropFirst, que tiene criterios de filtrado muy simples, el operador filterutiliza el cierre en lugar de un tipo primitivo. Este es un caso más complicado. ¿Cómo guardamos y difundimos un cierre?

filter(_:)

Vuelve a publicar todos los elementos que coinciden con el cierre dado.

developer.apple.com


Echemos un vistazo filtermás de cerca al método .

func filter(_ isIncluded: @escaping (Self.Output) -> Bool) -> Publishers.Filter<Self>

Su cierre isIncludedtoma un tipo universal y devuelve un valor booleano.

¿Hay algo en Foundation que represente condiciones lógicas y devuelva un valor lógico? Me recuerda a algo?

Filtrar con NSPredicate


La respuesta es NSPredicate. Si podemos guardar las condiciones de filtrado como expresiones en formato de cadena, simplemente podemos pasar el valor de la secuencia y usarlo NSPredicatepara evaluar los resultados.

Continuemos y agreguemos filtera la lista.

enum Operator {
 case delay(seconds: Double)
 case dropFirst(count: Int)
 case filter(expression: String)
}

Todo lo que necesitamos hacer es filtrar expresiones como %d !=3o %@ != “D”; por lo tanto, la expresión es un tipo apropiado. Del mismo modo, deberíamos poder mover la lista filter a Publisher.

extension Operator {
func applyPublisher<T>(_ publisher: AnyPublisher<T, Never>) -> AnyPublisher<T, Never> { 
 switch self {
   case .filter(let expression):
   return publisher.filter { value in
               NSPredicate(format: expression,
                           argumentArray: [value])
                .evaluate(with: nil) }.eraseToAnyPublisher()
      
     //   
 }}}

Según lo planeado, enviamos la expresión NSPredicatejunto con el valor enviado desde Publisher.

Tenga en cuenta que NSPredicateacepta una serie de argumentos. Por lo tanto, debería funcionar con alguna modificación, incluso cuando los valores asumen el formato de tuplas, lo cual es muy común en escenarios reactivos. Volveremos a esto en el futuro cuando hablemos de operadores combinados.



Como puede ver, Filter Stream se agrega a esta matriz guardada de declaraciones y se convierte en Publisher para filtrar el número 3 de los valores más altos.



En el próximo episodio: Guardar operadores de transformación, mapa y escaneo


En la demostración GIF, puede encontrar que la lista de operadores está bastante vacía. En las próximas semanas, vamos a llenarlo con varios tipos de operadores: operadores de transformación mapy scan.
Puede encontrar el código fuente en este repositorio combine-magic-swifui en la carpeta combine-playground.

Esperamos sus comentarios y lo invitamos a abrir el día en el curso .

All Articles