Je me rends compte qu'il y a beaucoup de code ici pour une question SO, mais c'est le meilleur que je peux faire pour l'instant ... Vous pouvez simplement copier/coller le code dans un terrain de jeu rx pour voir le problème.Pourquoi l'événement d'achèvement empêche-t-il le passage de ce test?
Sur la ligne 89, il y a un morceau de code let creds = Observable.just(credentials)//.concat(Observable.never())
commenté. Si je supprime le //
et autorise la concat, le code passera son test. Quelqu'un peut-il donner une idée de la raison pour laquelle ce code échoue au test si creds
est autorisé à envoyer un événement d'achèvement?
import Foundation
import RxSwift
import RxCocoa
import UIKit
typealias Credentials = (email: String, password: String)
struct User {
let id: String
let properties: [Property]
}
struct Property {
let id: String
let name: String
}
struct LoginParams {
let touchIDPossible: Bool
}
class LoginScreen {
var attemptLogin: Observable<Credentials> {
assert(_attemptLogin == nil)
_attemptLogin = PublishSubject()
return _attemptLogin!
}
var _attemptLogin: PublishSubject<(email: String, password: String)>?
}
class DashboardScreen {
func display(property: Observable<Property?>) {
property.subscribe(onNext: { [unowned self] in
self._property = $0
}).disposed(by: bag)
}
var _property: Property?
let bag = DisposeBag()
}
class Interface {
func login(params: LoginParams) -> Observable<LoginScreen> {
assert(_login == nil)
_login = PublishSubject()
return _login!
}
func dashboard() -> Observable<DashboardScreen> {
assert(_dashboard == nil)
_dashboard = PublishSubject()
return _dashboard!
}
var _login: PublishSubject<LoginScreen>?
var _dashboard: PublishSubject<DashboardScreen>?
let bag = DisposeBag()
}
class Server {
func user(credentials: Credentials) -> Observable<User> {
assert(_user == nil)
_user = PublishSubject()
return _user!
}
func property(id: String) -> Observable<Property> {
assert(_property == nil)
_property = PublishSubject()
return _property!
}
var _user: PublishSubject<User>?
var _property: PublishSubject<Property>?
}
class Coordinator {
init(interface: Interface, server: Server) {
self.interface = interface
self.server = server
}
func start() {
let credentials = (email: "foo", password: "bar")
// remove the `//` and the test will pass. Why does it fail when `creds` completes?
let creds = Observable.just(credentials)//.concat(Observable.never())
let autoUser = creds.flatMap {
self.server.user(credentials: $0)
.materialize()
.filter { !$0.isCompleted }
}.shareReplayLatestWhileConnected()
let login = autoUser.filter { $0.error != nil }
.flatMap { _ in self.interface.login(params: LoginParams(touchIDPossible: false)) }
let attempt = login.flatMap { $0.attemptLogin }
.shareReplayLatestWhileConnected()
let user = attempt.flatMap {
self.server.user(credentials: $0)
.materialize()
.filter { !$0.isCompleted }
}.shareReplayLatestWhileConnected()
let propertyID = Observable.merge(autoUser, user).map { $0.element }
.filter { $0 != nil }.map { $0! }
.map { $0.properties.sorted(by: { $0.name < $1.name }).map({ $0.id }).first }
let property = propertyID.filter { $0 != nil }.map { $0! }
.flatMap { self.server.property(id: $0)
.map { Optional.some($0) }
.catchErrorJustReturn(nil)
}.debug("property").shareReplayLatestWhileConnected()
let dashboard = property.flatMap { _ in self.interface.dashboard() }
dashboard.map { $0.display(property: property) }
.subscribe()
.disposed(by: bag)
}
let interface: Interface
let server: Server
let bag = DisposeBag()
}
do {
let interface = Interface()
let server = Server()
let coordinator = Coordinator(interface: interface, server: server)
coordinator.start()
assert(server._user != nil)
let simpleProperty = Property(id: "bar", name: "tampa")
let user = User(id: "foo", properties: [simpleProperty])
server._user?.onNext(user)
server._user?.onCompleted()
server._user = nil
assert(interface._login == nil)
assert(server._property != nil)
let property = Property(id: "bar", name: "tampa")
server._property!.onNext(property)
server._property!.onCompleted()
server._property = nil
assert(interface._dashboard != nil)
let dashboard = DashboardScreen()
interface._dashboard?.onNext(dashboard)
interface._dashboard?.onCompleted()
assert(dashboard._property != nil)
print("test passed")
}
Voici la sortie du code tel qu'il est au-dessus:
2017-06-01 22:22:42.534: property -> subscribed
2017-06-01 22:22:42.552: property -> Event next(Optional(__lldb_expr_134.Property(id: "bar", name: "tampa")))
2017-06-01 22:22:42.557: property -> Event completed
2017-06-01 22:22:42.557: property -> isDisposed
2017-06-01 22:22:42.559: property -> subscribed
assertion failed: file MyPlayground.playground, line 159
Pourquoi le property
étant abonné à après il a été disposé?
Voici la sortie si vous supprimez le \\
:
2017-06-01 22:23:51.540: property -> subscribed
2017-06-01 22:23:51.553: property -> Event next(Optional(__lldb_expr_136.Property(id: "bar", name: "tampa")))
test passed
Puisque nous n'avons pas vos numéros de ligne, pouvez-vous au moins ajouter un commentaire au code à propos de l'échec de l'assertion (ligne 159)? – ctietze
Désolé, c'est la dernière assertion qui échoue. –