LoginSignup
9
8

More than 5 years have passed since last update.

RxSwiftの新しいSingle, Maybe, Completableのソースを読んでみた

Last updated at Posted at 2017-04-17

RxSwiftに新しく追加されたSingle, Maybe, Completable で新しいUnitsたちを調べるのにRxSwiftはドキュメントがなかったので、ソースを読んで見たメモ。

実装ファイル

実装はこちら:point_right_tone1: RxSwift/PrimitiveSequence.swift

新しいUnitsは Traits というGroupと分類されている。
Traits = 性質という意味。 なるほど。

RxSwift_PrimitiveSequence_swift_at_master_·_ReactiveX_RxSwift.png

元となる構造体の定義

まず、PrimitiveSequence というstructが定義されていている
このstructにはGenericsで Trait(性質)Element(要素) が指定できる。
ElementsObservableのレスポンスの型になる。

PrimitiveSequence
/// Observable sequences containing 0 or 1 element.
public struct PrimitiveSequence<Trait, Element> {
    fileprivate let source: Observable<Element>

    init(raw: Observable<Element>) {
        self.source = raw
    }
}

新しいUnitsの定義

Units
/// Sequence containing exactly 1 element
public enum SingleTrait { }
/// Represents a push style sequence containing 1 element.
public typealias Single<Element> = PrimitiveSequence<SingleTrait, Element>

/// Sequence containing 0 or 1 elements
public enum MaybeTrait { }
/// Represents a push style sequence containing 0 or 1 element.
public typealias Maybe<Element> = PrimitiveSequence<MaybeTrait, Element>

/// Sequence containing 0 elements
public enum CompletableTrait { }
/// Represents a push style sequence containing 0 elements.
public typealias Completable = PrimitiveSequence<CompletableTrait, Swift.Never>

SingleTraitMaybeTraitCompletableTrait とそれぞれの性質を表すenumが定義されてる。
SingleMaybeCompletable が上述の PrimitiveSequence の typealiasとして定義されてる。

Swift.Neverは初めて知った。何も返さないことはVoidじゃなくて Never で表すらしい。
(Never - Swift Standard Library | Apple Developer Documentation)

PrimitiveSequenceTypeのプロトコル定義

PrimitiveSequenceType
/// Observable sequences containing 0 or 1 element
public protocol PrimitiveSequenceType {
    /// Additional constraints
    associatedtype TraitType
    /// Sequence element type
    associatedtype ElementType

    // Converts `self` to primitive sequence.
    ///
    /// - returns: Observable sequence that represents `self`.
    var primitiveSequence: PrimitiveSequence<TraitType, ElementType> { get }
}

extension PrimitiveSequence: PrimitiveSequenceType {
    /// Additional constraints
    public typealias TraitType = Trait
    /// Sequence element type
    public typealias ElementType = Element

    // Converts `self` to primitive sequence.
    ///
    /// - returns: Observable sequence that represents `self`.
    public var primitiveSequence: PrimitiveSequence<TraitType, ElementType> {
        return self
    }
}

ここで、PrimitiveSequenceType のプロトコルが定義される。
正直ここで Protocolを定義するがよくわかっていない。。。なんでだろ?
今後の似たようなUnitが出てきたにも対応できるように?:thinking:
ジェネリクスをtypealiasとしておいた方が、 後術のprotocol extensionは書きやすくなる気がする。

PrimitiveSeaquenceをObservableConvertibleTypeに適合

PrimitiveSequence
extension PrimitiveSequence: ObservableConvertibleType {
    /// Type of elements in sequence.
    public typealias E = Element

    /// Converts `self` to `Observable` sequence.
    ///
    /// - returns: Observable sequence that represents `self`.
    public func asObservable() -> Observable<E> {
        return source
    }
}

ObservableConvertibleType に適合させます。
とすることで、PrimitiveSequence はObservableにもなれます
狭い川は広くすることはできる。逆は不可。

各Unitsごと実装

その後は各性質ごとにEventや、createsubscribe 等の実装がされる。

SingleEvent
public enum SingleEvent<Element> {
    /// One and only sequence element is produced. (underlying observable sequence emits: `.next(Element)`, `.completed`)
    case success(Element)

    /// Sequence terminated with an error. (underlying observable sequence emits: `.error(Error)`)
    case error(Swift.Error)
}

各性質ごとのfunctionの実装は PrimitiveSequenceType のExtensionとして実装される。
where でジェネリクスの型をを指定することによって、適合する場合のみこのextensionが使えるようになる。

PrimitiveSequenceType(SingleTrait)
extension PrimitiveSequenceType where TraitType == SingleTrait {
    public typealias SingleObserver = (SingleEvent<ElementType>) -> ()

    public func subscribe(_ observer: @escaping (SingleEvent<ElementType>) -> ()) -> Disposable {
        var stopped = false
        return self.primitiveSequence.asObservable().subscribe { event in
            if stopped { return }
            stopped = true

            switch event {
            case .next(let element):
                observer(.success(element))
            case .error(let error):
                observer(.error(error))
            case .completed:
                rxFatalError("Singles can't emit a completion event")
            }
        }
    } 

   // その他の実装は省略
}

Singlesubscribe を見てもわかるように、success か、error しか流れない。
completedが流れてくるのは Single の仕様的にありえないので、fatalErrorでアプリが落ちる。

そのほか

そのほかの共通的な mapfilterなどのオペレーターは whereなしの PrimitiveSequenceType のextensionとして実装。

9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8