rxswift bind (onNext: VS подписаться (onNext: - PullRequest
3 голосов
/ 22 марта 2019

У меня 2 вопроса:

  1. Какая разница между 'bind (onNext:' и 'subscribe (onNext:'?
struct Info {
    var index: Int?
    var data: String?
}

let infoData: BehaviorRelay<Info> = BehaviorRelay<Info>(value: Info())
var osInfo: Observable<String> { return self.infoData.map({ return $0.data }).distinctUntilChanged() }

osInfo.bind { (target) in
    print("bind!")
    }.disposed(by: self.disposeBag)

osInfo.subscribe { (target) in
    print("subscribe!")
    }
    .disposed(by: self.disposeBag)
  1. a не имеет asObservable (), но хорошо исполняемый. В чем разница а и б?
a. var osInfo: Observable<String> { return self.infoData.map({ return $0.data }).distinctUntilChanged() }
b. var osInfo: Observable<String> { return self.infoData.asObservable().map({ return $0.data }).distinctUntilChanged() }

1 Ответ

4 голосов
/ 22 марта 2019

Какая разница между 'bind (onNext:' и 'subscribe (onNext:'?

Если мы проверим реализацию bind(...), мы обнаружим, что она ничего не делает, а просто использует subscribe(...) underhood и вылетает в Debug при ошибке:

/**
Subscribes an element handler to an observable sequence. 

In case error occurs in debug mode, `fatalError` will be raised.
In case error occurs in release mode, `error` will be logged.

- parameter onNext: Action to invoke for each element in the observable sequence.
- returns: Subscription object used to unsubscribe from the observable sequence.
*/
public func bind(onNext: @escaping (E) -> Void) -> Disposable {
    return subscribe(onNext: onNext, onError: { error in
        rxFatalErrorInDebug("Binding error: \(error)")
    })
}

Используя bind(onNext), вы можете указать, что поток никогда не должен выдавать ошибку и вас интересуют только события элемента.

Таким образом, вы должны использовать subscribe(onNext:...), когда вас интересуют события ошибки / завершения / удаления, и bind(onNext...) в противном случае. Но поскольку он является частью RxCocoa, а не RxSwift, я обычно использую subscribe везде.

a не имеет asObservable (), но хорошо исполняемый. В чем разница а и б?

map(...) - функция, объявленная в ObservableType и возвращающая новый Observable

Начнем с ObservableType.
ObservableType - это протокол, который требует только одного метода: subscribe(...), это позволяет ему создавать реализацию по умолчанию func asObservable().
Для вас это означает, что вы можете создать Observable из любого типа, соответствующего ObservableType.

/// Represents a push style sequence.
public protocol ObservableType : ObservableConvertibleType {
    func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E
}
extension ObservableType {
    /// Default implementation of converting `ObservableType` to `Observable`.
    public func asObservable() -> Observable<E> {
        // temporary workaround
        //return Observable.create(subscribe: self.subscribe)
        return Observable.create { o in
            return self.subscribe(o)
        }
    }
}

Таким образом, каждый раз, когда вы вызываете asObservable() underhood, RxSwift просто создает новую оболочку Observable вокруг вашего потока.

И если вы проверите источник BehaviourRelay, то обнаружите, что он также соответствует ObservableType. Таким образом, вы можете создать Observable из него в любое время:

public final class BehaviorRelay<Element>: ObservableType { ... }

Теперь давайте проверим map функцию:

extension ObservableType {

    /**
     Projects each element of an observable sequence into a new form.

     - seealso: [map operator on reactivex.io](http://reactivex.io/documentation/operators/map.html)

     - parameter transform: A transform function to apply to each source element.
     - returns: An observable sequence whose elements are the result of invoking the transform function on each element of source.

     */
    public func map<R>(_ transform: @escaping (E) throws -> R)
        -> Observable<R> {
        return self.asObservable().composeMap(transform)
    }
}

Как и ожидалось map просто позвоните asObservable() внутрь и работайте на новом Observable.

Если мы «развернем» map, мы получим:

var osInfoA: Observable<String> {
    return infoData
        .asObservable()
        .composeMap { $0.data }
        .distinctUntilChanged()
}
var osInfoB: Observable<String> {
    return infoData
        .asObservable()
        .asObservable()
        .composeMap { $0.data }
        .distinctUntilChanged()
}

Конечно, он не скомпилируется, поскольку composeMap является внутренней функцией, но у вас есть основная идея.
Вызов asObservable до того, как другие операторы являются избыточными (большинство операторов определены в ObservableType) и просто добавляет небольшие накладные расходы.

...