RxSwift: дополнительная удобная функция распаковки?

В настоящее время я создал функцию unwrapOptional для безопасного развертывания необязательного ввода в потоке.

    func unwrapOptional<T>(x: Optional<T>) -> Observable<T> {
       return x.map(Observable.just) ?? Observable.empty()
    }

    let aOpt: String? = "aOpt"
    _ = Observable.of(aOpt).flatMap(unwrapOptional).subscribeNext { x in print(x)}

    let aNil: String? = nil
    _ = Observable.of(aNil).flatMap(unwrapOptional).subscribeNext { x in print(x)}

    let a: String = "a"
    _ = Observable.of(a).flatMap(unwrapOptional).subscribeNext { x in print(x)}

   // output 
    aOpt
    a

Я хочу заархивировать, чтобы вместо использования flatMap(unwrapOptional) создать удобную функцию, например

Observable.of(a).unwrapOptional()

Что-то я пытался сделать, но он не компилируется ...

extension ObservableType {
    func unwrapOptional<O : ObservableConvertibleType>() -> RxSwift.Observable<O.E> {
        return self.flatMap(unwrapOptional)
    }
}

person LoGary    schedule 19.04.2016    source источник


Ответы (4)


Вы хотите, чтобы метод unwrapOptional работал только с наблюдаемыми объектами, имеющими необязательный тип.

Таким образом, вам нужно каким-то образом ограничить Element из Observable, чтобы соответствовать протоколу Optional.

extension Observable where Element: OptionalType {
    /// Returns an Observable where the nil values from the original Observable are
    /// skipped
    func unwrappedOptional() -> Observable<Element.Wrapped> {
        return self.filter { $0.asOptional != nil }.map { $0.asOptional! }
    }
}

К сожалению, Swift не определяет такой протокол (OptionalType). Так что вам тоже нужно определить это самостоятельно

/// Represent an optional value
///
/// This is needed to restrict our Observable extension to Observable that generate
/// .Next events with Optional payload
protocol OptionalType {
    associatedtype Wrapped
    var asOptional:  Wrapped? { get }
}

/// Implementation of the OptionalType protocol by the Optional type
extension Optional: OptionalType {
    var asOptional: Wrapped? { return self }
}
person tomahh    schedule 22.04.2016

оформить заказ unwrap на странице https://github.com/RxSwiftCommunity/RxSwift-Ext :)

или https://github.com/RxSwiftCommunity/RxOptional

На данный момент вы должны использовать RxOptional для личных нужд
Однако RxSwift-Ext будет расти экспоненциально в следующие 2-3 месяца :)

person Pham Hoan    schedule 19.04.2016

RxSwift теперь поддерживает compactMap (). Итак, теперь вы можете делать такие вещи, как:

func unwrap(_ a: Observable<Int?>) -> Observable<Int> {
  return a.compactMap { $0 }
}
person chunkyguy    schedule 18.06.2020

Вот версия без OptionalType (из https://stackoverflow.com/a/36788483/13000)

extension Observable {

    /// Returns an `Observable` where the nil values from the original `Observable` are skipped
    func unwrap<T>() -> Observable<T> where Element == T? {
        self
            .filter { $0 != nil }
            .map { $0! }
    }
}
person deanWombourne    schedule 06.05.2020