8

Currently I have created a function unwrapOptional to safely unwrap the optional input in the stream.

    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

What I want to archive is to create a handy function instead of using flatMap(unwrapOptional), for example

Observable.of(a).unwrapOptional()

Something I tried to do, but it never compiles...

extension ObservableType {
    func unwrapOptional<O : ObservableConvertibleType>() -> RxSwift.Observable<O.E> {
        return self.flatMap(unwrapOptional)
    }
}
Dani Pralea
  • 4,545
  • 2
  • 31
  • 49
LoGary
  • 322
  • 2
  • 3
  • 13

4 Answers4

10

You want the unwrapOptional method to only work on observables that have optional type.

So you somehow have to constraint the Element of Observable to conform to the Optional protocol.

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! }
    }
}

Unfortunately, Swift does not define such a protocol (OptionalType). So you also need to define it yourself

/// 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 }
}
tomahh
  • 13,441
  • 3
  • 49
  • 70
6

checkout unwrap at https://github.com/RxSwiftCommunity/RxSwift-Ext :)

or https://github.com/RxSwiftCommunity/RxOptional

For now, you should use RxOptional for your personal needs
However, RxSwift-Ext will be growth exponentially in next 2-3 months :)

Pham Hoan
  • 2,107
  • 2
  • 20
  • 34
4

RxSwift now supports compactMap(). So, now you can do things like:

func unwrap(_ a: Observable<Int?>) -> Observable<Int> {
  return a.compactMap { $0 }
}
chunkyguy
  • 3,509
  • 1
  • 29
  • 34
3

Here's a version without needing OptionalType (from 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! }
    }
}
deanWombourne
  • 38,189
  • 13
  • 98
  • 110