72 votes

Comment utiliser BehaviorRelay comme alternative à la variable dans RxSwift?

Comme de RxSwift4, Variable est déplacé Deprecated.swift marquage de l'éventuelle dépréciation de l' Variable à l'avenir. Un autre a proposé de Variable est BehaviorRelay. Alors que l'affichage de cette question, que je ne pouvais pas trouver beaucoup de tutoriel sur le web à l'aide d' BehaviorRelay am poster une telle question fondamentale ici, dans la.

Supposons que j'ai un webService appel en cours et j'recevoir un bloc de données qui est JSONArray, sur l'analyse d'objet JSON, un par un je mettre à jour ma Variable de la valeur de la propriété

Voici ma déclaration de variable

var myFilter = Variable<[MyFilterModel]>([MyFilterModel(data: "{:}")])

sur l'obtention d'un nouvel élément à chaque fois que je voudrais mettre à jour ma Variable

myFilter.value.append(newModel)

En tant que Variable a été de se lier à CollectionView, collectionVie permettrait de mettre à jour son INTERFACE utilisateur immédiatement avec le nouvel objet ajouté.

Problème avec BehaviorRelay

Maintenant, ma déclaration ressemble à

var myFilter = BehaviorRelay<[MyFilterModel]>(value: [MyFilterModel(data: "{:}")])

Mais la question la plus importante est myFilter.value est en lecture seule. Alors, évidemment

myFilter.value.append(newModel) 

n'est pas une solution. J'ai compris que je peux utiliser, accept plutôt.

Mais maintenant, quand j'essaie d'analyser chaque élément de réponse et de mise à jour de la valeur de myFilter

self?.expertsFilter.accept(newModel)

La déclaration ci-dessus donne une erreur en citant

Ne peut pas convertir la valeur de NewModel attendus arguement type [NewModel]

Évidemment, il attend un tableau et non pas un élément individuel.

Solution de contournement:

Solution 1:

Donc, une solution est d'accumuler de l'ensemble de la réponse dans un tableau temporaire et une fois fait déclencher self?.expertsFilter.accept(temporary_array)

Solution 2:

Si je dois envoyer onNext événement à l'abonné sur l'analyse de chaque élément, j'ai besoin de copier la valeur de l'auto?.expertsFilter à nouveau Tableau, ajouter la nouvelle analysé élément et le retour de la nouvelle matrice.

Solution 3:

Se débarrasser de l' BehaviorRelay et l'utilisation BehaviorSubject/PublishSubject

Deux premiers sons déprimant, car il peut y avoir un besoin de déclencher l'INTERFACE utilisateur sur l'analyse de chaque élément, je ne peux pas attendre jusqu'à la totalité de la réponse est analysée. Alors, évidemment, la solution 1 n'est pas beaucoup d'utilisation.

La deuxième solution est beaucoup plus horrible, parce qu'il crée un nouveau tableau (je sais que c'est temporaire et sera publié) à chaque fois pour envoyer onNext événement.

Question:

Parce qu' BehaviorRelay est proposée comme une alternative à l' Variable suis en dilemme, je suis en utilisant accept correctement?? Est-il un meilleur moyen de le résoudre?

S'il vous plaît aider

39voto

daltonclaybrook Points 3944

Avez-vous envisagé de créer simplement un nouveau tableau à partir de la valeur existante sur le relais, d’ajouter, puis d’appeler accept ?

 myFilter.accept(myFilter.value + [newModel])
 

13voto

retendo Points 922

S'appuyant sur la réponse de Dalton , voici une extension pratique:

 extension BehaviorRelay where Element: RangeReplaceableCollection {
    func acceptAppending(_ element: Element.Element) {
        accept(value + [element])
    }
}
 

10voto

Ashkan Sarlak Points 21

J'ai écrit cette extension pour le remplacement d' Variables avec BehaviorRelays. Vous pouvez ajouter quelle que soit la méthode que vous avez besoin en fonction de ce modèle de migrer facilement.

public extension BehaviorRelay where Element: RangeReplaceableCollection {

    public func insert(_ subElement: Element.Element, at index: Element.Index) {
        var newValue = value
        newValue.insert(subElement, at: index)
        accept(newValue)
    }

    public func insert(contentsOf newSubelements: Element, at index: Element.Index) {
        var newValue = value
        newValue.insert(contentsOf: newSubelements, at: index)
        accept(newValue)
    }

    public func remove(at index: Element.Index) {
        var newValue = value
        newValue.remove(at: index)
        accept(newValue)
    }
}

Au lieu de Variable.value.funcName, maintenant vous écrivez BehaviorRelay.funcName.

L'idée d'utiliser where Element: RangeReplaceableCollection clause vient de retendo réponse

Notez également que l' index est de type Element.Index, pas Int ou tout autre chose.

2voto

Maxim Volgin Points 269

Je ferais quelque chose comme ça -

 let requests = PublishSubject<Observable<ServerResponse>>.create()
let responses: Observable<ServerResponse> = requests.switchLatest()

let parsed: Observable<[ParsedItem]> = responses
  .flatMap { Observable.from($0).map { parse($0) }.toArray() }

parsed.bind(to: ui)

// repeated part
let request1: Observable<ServerResponse> = servive.call()
request.onNext(request1)
 

1voto

Reimond Hill Points 2

AshKan répond que c’est génial, mais je suis venu ici pour chercher une méthode manquante dans la solution. Ajouter:

 extension BehaviorRelay where Element: RangeReplaceableCollection {

    func append(_ subElement: Element.Element) {
        var newValue = value
        newValue.append(subElement)
        accept(newValue)
    }

} 
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X