[iOS] RxSwiftのPlaygroundのサンプルの出力

2019/02/2

こんにちは。きんくまです。

RxSwiftを勉強中です。それで、いろいろと調べていたのですが、イマイチ全体像が見えてこない!
でこれは何なのか?と考えたら、一番の基本となるものが何なのかわからないことに気がつきました。

そんなとき、公式のリポジトリにあるPlaygroundを写経してみたところ、ベースとなるものがわかった気がしました。

で、もう少しいろいろと調べないといけないのですが、毎回「これって何するやつ?」というのを調べるのが面倒くさいです。

なので、このページにPlaygroundに乗っていたやつを1ページに全て書いてしまい、Cmd + f で検索できたら出力がすぐに確認できて便利だなーと思った、メモ記事になります。

コードは基本的にPlaygroundのままなのですが、公式のやつは絵文字ばっかりつかってて、見づらいので普通のアルファベットとかに直しています。

バージョン

1
2
pod 'RxSwift',    '~> 4.4.0'
pod 'RxCocoa',    '~> 4.4.0'

Creating and Subscribing to Observables

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
//以下のimportはこのクラスだけ載せていますが、以降は省略します
import UIKit
import RxSwift
import RxCocoa
 
class Playground_SubscribingToObservables {
     
    var disposeBag = DisposeBag()
     
    public init(){
         
    }
     
    func neverSample(){
        print("never start === ")
        let neverSequence = Observable<String>.never()
         
        neverSequence.subscribe { _ in
            print("never")
        }.disposed(by: disposeBag)
         
        /*
         何もイベントを発行しない
         */
    }
     
    func emptySample(){
        print("empty start === ")
        Observable<Int>.empty()
            .subscribe{ event in
                print("event \(event)")
            }.disposed(by: disposeBag)
         
        /*
         completedだけemit
          
         empty start ===
         event completed
         */
    }
     
    func just(){
        print("just start ===")
        Observable<String>.just("Hello world")
            .subscribe{ event in
                print("subsc --")
                print("event \(event.event)")
                print("elem \(String(describing: event.element))")
            }.disposed(by: disposeBag)
         
        /*
         1個のelementからObservableを作成
          
         just start ===
         subsc --
         event next(Hello world)
         elem Optional("Hello world")
         subsc --
         event completed
         elem nil
          
         */
    }
     
    func ofSample(){
        print("of start ===")
        Observable<String>.of("a", "b", "c")
            .subscribe(onNext:{ event in
                print("onNext: \(event)")
            }, onCompleted: {
                print("onCompleted")
            }).disposed(by: disposeBag)
         
        /*
         引数のelementsからObservableを作成
          
         of start ===
         onNext: a
         onNext: b
         onNext: c
         onCompleted
         */
    }
     
    func fromSample(){
        print("from start ===")
        Observable<String>.from(["a", "b", "c"])
            .subscribe(onNext: { event in
                print("on next: \(event)")
            }).disposed(by: disposeBag)
         
        /*
         配列からObservableを作成
          
         from start ===
         on next: a
         on next: b
         on next: c
         */
    }
     
    func createSample(){
        print("create start ===")
        let myjust = { (elem:String) -> Observable<String> in
            return Observable.create { observer in
                observer.onNext(elem)
                observer.onCompleted()
                return Disposables.create()
            }
        }
         
        myjust("hello world").subscribe { print($0) }
            .disposed(by: disposeBag)
         
        /*
         独自のObservableを作成
          
         create start ===
         next(hello world)
         completed
         */
    }
     
    func range(){
        print("start range ===")
        //2から4まで3つnextする
        Observable.range(start: 2, count: 3)
            .subscribe{ print($0)}
            .disposed(by: disposeBag)
         
        /*
         startからcount分のelementをemit
          
         start range ===
         next(2)
         next(3)
         next(4)
         completed
         */
    }
     
    func repeatElement(){
        print("start repeat elem ===")
        //5回 k が next
        Observable.repeatElement("k")
            .take(5)
            .subscribe { print($0) }
            .disposed(by: disposeBag )
         
        /*
         引数回elementをemit
          
         start repeat elem ===
         next(k)
         next(k)
         next(k)
         next(k)
         next(k)
         completed
         */
    }
     
    func generate(){
        print("generate start ===")
         
        Observable.generate(
                initialState: 5,
                condition: { $0 < 15 },
                iterate: { $0 + 3 }
            ).subscribe { print($0) }
            .disposed(by: disposeBag)
         
        /*
         複雑な条件のObservableを生成
          
         generate start ===
         next(5)
         next(8)
         next(11)
         next(14)
         completed
         */
    }
     
    func deferredSample(){
        print("deferred start ===")
         
        var count = 1
         
        let mySeqence =  Observable<String>.deferred {
            print("Creating \(count)")
            count += 1
             
            return Observable.create { observer in
                print("Emitting...")
                observer.onNext("foo")
                observer.onNext("bar")
                observer.onNext("baz")
                return Disposables.create()
            }
        }
         
        mySeqence
            .subscribe(onNext: { print($0) } )
            .disposed(by: disposeBag)
         
        mySeqence
            .subscribe(onNext: { print($0) } )
            .disposed(by: disposeBag)
         
        /*
         subscribeされるまで次のObservableを作らない。
         subscribeされたら次のやつを作る
          
         deferred start ===
         Creating 1
         Emitting...
         foo
         bar
         baz
         Creating 2
         Emitting...
         foo
         bar
         baz
         */
    }
     
    func errorSample(){
        print("error ===")
         
        let info:[String:Any] =  ["error_message":"dayo"]
        //Observable<String> の <String> を書かないとエラー
        Observable<String>.error(NSError(domain: "myerror domain",
                                 code: 150, userInfo:info))
            .subscribe(onError:{ (error) in
                let error2 = error as NSError
                print(error2)
            }).disposed(by: disposeBag)
         
        /*
         itemはemitしなけれど、すぐにerrorを発行
          
         error ===
         Error Domain=myerror domain Code=150 "(null)" UserInfo={error_message=dayo}
         */
    }
     
    func doOnSample(){
        print("do on ===")
         
        Observable<String>.from(["dog", "cat", "baz"])
            .do(onNext: { print("doOnNext:", $0) },
                onCompleted: { print("doOnCompleted") })
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
         
        /*
         emitするたびに、実行
          
         do on ===
         doOnNext: dog
         dog
         doOnNext: cat
         cat
         doOnNext: baz
         baz
         doOnCompleted
         */
    }
}

Working with Subjects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
class Playground_subjects {
    public init(){}
    let disposeBag = DisposeBag()
     
    func publishSubject(){
        print("PublishSubject ===")
        let subject = PublishSubject<String>()
        subject
            .subscribe(onNext: { print("id1 -> ", "onNext:", $0 )})
            .disposed(by: disposeBag)
         
        subject.onNext("foo")
        subject.onNext("bar")
         
        subject
            .subscribe(onNext: { print("id2 -> ", "onNext:", $0) })
            .disposed(by: disposeBag)
         
        subject.onNext("foo2")
        subject.onNext("bar2")
         
        /*
         subscribeしたときは何もeventを出さない
         次のnextから受け取る
          
         PublishSubject ===
         id1 ->  onNext: foo
         id1 ->  onNext: bar
         id1 ->  onNext: foo2
         id2 ->  onNext: foo2
         id1 ->  onNext: bar2
         id2 ->  onNext: bar2
         */
    }
     
    func replaySubject() {
        print("ReplaySubject ===")
        let subject = ReplaySubject<String>.create(bufferSize: 1)
         
        subject
            .subscribe(onNext: { print("id1 -> ", "onNext:", $0 )})
            .disposed(by: disposeBag)
         
        subject.onNext("foo")
        subject.onNext("bar")
         
        subject
            .subscribe(onNext: { print("id2 -> ", "onNext:", $0) })
            .disposed(by: disposeBag)
         
        subject.onNext("foo2")
        subject.onNext("bar2")
         
        /*
         初期化時のbufferSizeだけ subscribe したときに event が出る
         ReplaySubject ===
         id1 ->  onNext: foo
         id1 ->  onNext: bar
         id2 ->  onNext: bar
         id1 ->  onNext: foo2
         id2 ->  onNext: foo2
         id1 ->  onNext: bar2
         id2 ->  onNext: bar2
         */
    }
     
    func behaviorSubject(){
        print("BehaviorSubject === ")
        let subject = BehaviorSubject(value: "behavior initial value!!")
         
        subject
            .subscribe(onNext: { print("id1 -> ", "onNext:", $0 )})
            .disposed(by: disposeBag)
         
        subject.onNext("foo")
        subject.onNext("bar")
         
        subject
            .subscribe(onNext: { print("id2 -> ", "onNext:", $0) })
            .disposed(by: disposeBag)
         
        subject.onNext("foo2")
        subject.onNext("bar2")
         
        subject
            .subscribe(onNext: { print("id3 -> ", "onNext:", $0 )})
            .disposed(by: disposeBag)
         
        subject.onNext("foo3")
        subject.onNext("bar3")
         
        /*
         subscribeした時点で最新のeventを受け取る
          
         BehaviorSubject ===
         id1 ->  onNext: behavior initial value!!
         id1 ->  onNext: foo
         id1 ->  onNext: bar
         id2 ->  onNext: bar
         id1 ->  onNext: foo2
         id2 ->  onNext: foo2
         id1 ->  onNext: bar2
         id2 ->  onNext: bar2
         id3 ->  onNext: bar2
         id1 ->  onNext: foo3
         id2 ->  onNext: foo3
         id3 ->  onNext: foo3
         id1 ->  onNext: bar3
         id2 ->  onNext: bar3
         id3 ->  onNext: bar3
         */
    }
}

Combining Operators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
class Playground_Operators {
    let disposeBag = DisposeBag()
     
    func startWith() {
        print("start with === ")
        Observable.of("foo", "bar", "baz")
            .startWith("1")
            .startWith("2")
            .startWith("3", "3-2", "3-3")
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        /*
         startWithのものの方が先にnextされる。
         startWithは最初に書いたものの方が最後に出力される
          
         start with ===
         3
         3-2
         3-3
         2
         1
         foo
         bar
         baz
         */
    }
     
    func merge(){
        print("start merge ===")
         
        let subject1 = PublishSubject<String>()
        let subject2 = PublishSubject<String>()
         
        Observable.of(subject1, subject2)
            .merge()
            .subscribe(onNext: { print("merged next:", $0)})
            .disposed(by: disposeBag)
         
//        subject1.subscribe(onNext: { print("subject1 next:", $0)})
//            .disposed(by: disposeBag)
//
//        subject2.subscribe(onNext: { print("subject2 next:", $0)})
//            .disposed(by: disposeBag)
         
        subject1.onNext("foo")
        subject1.onNext("bar")
        subject2.onNext("foo2")
        subject2.onNext("bar2")
        subject1.onNext("foo3")
        subject2.onNext("bar3")
         
        /*
         mergeされたものが1つのタイムラインにのっかって出てくる
          
         start merge ===
         merged next: foo
         merged next: bar
         merged next: foo2
         merged next: bar2
         merged next: foo3
         merged next: bar3
        */
    }
     
    func combineLatest(){
        print("combine latest === ")
        let strSubject = PublishSubject<String>()
        let intSubject = PublishSubject<Int>()
         
        Observable.combineLatest(strSubject, intSubject){ strElem, intElem in
            "combine: \(strElem), \(intElem)"
            }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
         
        strSubject.onNext("foo")
        strSubject.onNext("bar")
        intSubject.onNext(1)
        intSubject.onNext(2)
        strSubject.onNext("baz")
         
        /*
         個別にeventが出るのではなくて、同時に合わさったeventを発行する
         各Observableが少なくとも1回はEventを発行しないと開始しない.
         開始するときは、最新のものが使われる
         combine latest ===
         combine: bar, 1
         combine: bar, 2
         combine: baz, 2
         */
    }
     
    func combineLatest2() {
        print("combineLatest2 === ")
         
        let ken = Observable.just("Ken")
        let arr = Observable.from(["foo", "bar", "baz"])
        let num = Observable.of("1", "2", "3", "4")
         
        Observable.combineLatest([ken, arr, num]) {
            "combined: \($0[0]), \($0[1]), \($0[2]))"
        }.subscribe({ print($0) })
            .disposed(by: disposeBag)
         
        /*
         かなり特殊な例なんじゃないかな?使うことあるか?
         combineLatest2 ===
         next(combined: Ken, foo, 1))
         next(combined: Ken, bar, 1))
         next(combined: Ken, bar, 2))
         next(combined: Ken, baz, 2))
         next(combined: Ken, baz, 3))
         next(combined: Ken, baz, 4))
         completed
        */
    }
     
    func switchLatest() {
        print("switchLatest === ")
         
        let subject1 = BehaviorSubject(value: "foo")
        let subject2 = BehaviorSubject(value: "bar")
         
        let subjectsSubject = BehaviorSubject(value: subject1)
         
        subjectsSubject.asObservable()
            .switchLatest()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
         
        subject1.onNext("Mike")
        subject1.onNext("Paul")
         
        subjectsSubject.onNext(subject2)
         
        subject1.onNext("Nancy")
        subject2.onNext("Cathy")
         
        subjectsSubject.onNext(subject1) //※1
         
        /*
         event発行のものを途中で切り替えている
         切り替え後はeventを発行しない。
         しかし、また※1 で戻すとeventが流れる
          
         switchLatest ===
         foo
         Mike
         Paul
         bar
         Cathy
         Nancy
         */
    }
}

Transforming Operators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
class Playground_TransformingOp {
     
    let disposeBag = DisposeBag()
     
    public init(){}
     
    func map() {
        print("map ===")
        Observable.of(1, 2, 3)
            .map { $0 * $0 }
            .subscribe(onNext: { print($0)})
            .disposed(by: disposeBag)
         
        /*
         map ===
         1
         4
         9
         */
    }
     
    struct Player {
        let score: BehaviorSubject<Int>
        init(score: Int) {
            self.score = BehaviorSubject(value: score)
        }
    }
     
    func flatMap() {
        print("flatmap and flatmapLatest === ")
         
        let tom = Player(score: 80)
        let mike = Player(score: 90)
         
        let player = BehaviorSubject(value: tom)
         
        player
            // asObservableしなくてもSubjectはそのままsubscribeできた。
            // これは以前のバージョンだとできなかったのかも
            //.asObservable()
            //.flatMap{ $0.score.asObservable() }
             
            .flatMap{ $0.score }
            //.flatMapLatest{ $0.score }
             
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
         
        print("tom next")
        tom.score.onNext(85)
         
        print("change player to mike")
        player.onNext(mike)
         
        print("tom next")
        tom.score.onNext(95)
         
        print("mike next")
        mike.score.onNext(100)
         
        print("tom next")
        tom.score.onNext(110)
         
        print("change player to tom")
        player.onNext(tom)
         
        /*
         //playerがmikeを指した後もtomのeventが受け取られている
         flatmap ===
         80
         tom next
         85
         change player to mike
         90
         tom next
         95
         mike next
         100
         tom next
         110
         change player to tom
         110
          
         //tomの値を変えても、playerがmikeを指した後はeventを受け取らない
         //95の値が出ていない
         flatmapLatest ===
         80
         tom next
         85
         change player to mike
         90
         tom next
         mike next
         100
         tom next //ここでは出てない
         change player to tom //ここで変えたから出る
         110
         */
    }
     
    func scan() {
        print("scan ===")
         
        Observable.of(1, 3, 7, 15)
            .scan(4) { aggregateValue, newValue in
                print("scanned:", aggregateValue, newValue)
                return aggregateValue + newValue
            }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
         
        /*
         scan(1) のとき ===
         scanned: 1 1
         2
         scanned: 2 3
         5
         scanned: 5 7
         12
         scanned: 12 15
         27
          
         scan(4) のとき ===
         scanned: 4 1
         5
         scanned: 5 3
         8
         scanned: 8 7
         15
         scanned: 15 15
         30
         */
    }
}

Filtering and Conditional Operators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
class Playground_FilteringConditionalOperators {
     
    let bag = DisposeBag()
     
    func filter() {
        print("filter ===")
        Observable.of(
            "foo", "bar", "baz",
            "bar2", "foo2", "baz2",
            "foo3", "baz3", "bar3"
            ).filter{ $0.contains("foo") }
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         foo
         foo2
         foo3
         */
    }
     
    func distinctUntilChanged() {
        print("distinctUntilChanged ===")
        Observable.of("foo", "bar", "bar", "foo", "foo", "foo", "baz", "foo")
        .distinctUntilChanged()
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         同じ値が続いたときは、最初のもの以外は無視。
         新しいものが出たら、nextで出す
         foo
         bar
         foo
         baz
         foo
         */
    }
     
    func elementAt() {
        print("elementAt ===")
        Observable.of("1", "2", "3", "4")
            .elementAt(2)
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         indexで返す
         elementAt ===
         3
         */
    }
     
    func single1() {
        print("single1 ===")
        Observable.of("a", "b", "c")
            .single()
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
        /*
         最初のelementをemit
         single1 ===
         a
         */
    }
     
    func single2_4() {
        print("single2 ===")
         
        Observable.of("foo", "bar", "baz", "alpha", "beta", "gamma")
            .single { $0 == "alpha" }
            .subscribe { print($0) }
            .disposed(by: bag)
         
        /*
         正常終了
          
         single2 ===
         next(alpha)
         completed
         */
         
        print("single3 ===")
         
        Observable.of("foo", "bar", "baz", "foo", "bar", "baz")
            .single { $0 == "bar" }
            .subscribe { print($0) }
            .disposed(by: bag)
         
        /*
         エラー。該当条件が1つより多くマッチしているため
          
         single3 ===
         next(bar)
         error(Sequence contains more than one element.)
         */
         
        print("single4 ===")
         
        /*
         エラー。該当条件のelmentが見つからない
          
         single4 ===
         error(Sequence doesn't contain any elements.)
         */
         
        Observable.of("foo", "bar", "baz", "alpha", "beta", "gamma")
            .single { $0 == "delta" }
            .subscribe { print($0) }
            .disposed(by: bag)
    }
     
    func take() {
        print("take === ")
        Observable.of("a", "b", "c", "d", "e")
            .take(3)
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         最初からのn個を取る
         take ===
         a
         b
         c
         */
    }
     
    func takeLast() {
        print("takeLast ===")
        Observable.of("a", "b", "c", "d", "e")
            .takeLast(3)
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         後ろからn個を取る
         takeLast ===
         c
         d
         e
         */
    }
     
    func takeWhile() {
        print("takeWhile ===")
        Observable.of(1, 2, 3, 4, 5, 6)
            .takeWhile { $0 < 4 }
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         条件を満たしているものだけemit
         takeWhile ===
         1
         2
         3
         */
    }
     
    func takeUntil() {
        print("takeUntil ===")
         
        let sourceSequence = PublishSubject<String>()
        let referenceSequence = PublishSubject<String>()
         
        sourceSequence
            .takeUntil(referenceSequence)
            .subscribe { print($0) }
            .disposed(by: bag)
         
        sourceSequence.onNext("a")
        sourceSequence.onNext("b")
        sourceSequence.onNext("c")
         
        referenceSequence.onNext("d")
         
        sourceSequence.onNext("e")
        sourceSequence.onNext("f")
        sourceSequence.onNext("g")
         
        /*
         takeUntilの引数がemitするまでemitし続ける。
         引数がemitすると止まる(completed)
          
         takeUntil ===
         next(a)
         next(b)
         next(c)
         completed
         */
    }
     
    func skip() {
        print("skip ===")
         
        Observable.of("a", "b", "c", "d", "e", "f")
            .skip(2)
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         skipで指定した個数分だけとばしてからemit開始
          
         skip ===
         c
         d
         e
         f
         */
    }
     
    func skipWhile() {
        print("skipWhile ===")
         
        Observable.of(1, 2, 3, 4, 5, 6)
            .skipWhile { $0 < 4 }
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         該当条件まではemitしないが、該当条件の境界はemitする
          
         skipWhile ===
         4
         5
         6
         */
    }
     
    //skipWhileWithIndexはdeprecated!
//    func skipWhileWithIndex() {
//        print("skipWhileWithIndex ===")
//
//        Observable.of("a", "b", "c", "d", "e")
//            .skipWhileWithIndex()
//    }
     
    func skipUntil() {
        print("skipUntil ===")
        let sourceSequence = PublishSubject<String>()
        let referenceSequence = PublishSubject<String>()
         
        sourceSequence
            .skipUntil(referenceSequence)
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        sourceSequence.onNext("a")
        sourceSequence.onNext("b")
        sourceSequence.onNext("c")
         
        referenceSequence.onNext("d")
         
        sourceSequence.onNext("e")
        sourceSequence.onNext("f")
        sourceSequence.onNext("g")
         
        /*
         skipUntilの引数がemitするまでは待機。emitしたら流す
          
         skipUntil ===
         e
         f
         g
         */
    }
}

Mathematical and Aggregate Operators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class Playground_Math_AggregateOps {
     
    let bag = DisposeBag()
     
    func toArray() {
        print("toArray ===")
         
        Observable.range(start: 1, count: 10)
            .toArray()
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         sequenceをひとつの配列にまとめてemit
          
         toArray ===
         [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
         */
    }
     
    func reduce() {
        print("reduce === ")
         
        Observable.of(20, 300, 4000)
            .reduce(5, accumulator: +)
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         初期値とaccumulatorを使ってひとつの値に計算してからemit
          
         reduce ===
         4325
         */
         
        Observable.of(2, 3)
            .reduce(5, accumulator: *)
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         30
         */
    }
     
    func concat() {
        print("concat ===")
         
        let subject1 = BehaviorSubject(value: "1-a")
        let subject2 = BehaviorSubject(value: "1-b")
         
        let subjectsSubject = BehaviorSubject(value: subject1)
         
        subjectsSubject
            .concat()
            .subscribe { print($0) }
            .disposed(by: bag)
         
        subject1.onNext("1-c")
        subject1.onNext("1-d")
         
        subjectsSubject.onNext(subject2)
         
        subject2.onNext("2-I would be ignored")
        subject2.onNext("2-e")
        subject1.onCompleted()
        subject2.onNext("2-f")
         
        /*
         最初に指定したものがcompleteするまで待ってから次のものをemit
          
         concat ===
         next(1-a)
         next(1-c)
         next(1-d)
         next(2-e)
         next(2-f)
         */
    }
}

Connectable Operators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
func delay(_ delay: Double, closure: @escaping () -> Void) -> DispatchSourceTimer {
    let timer = DispatchSource.makeTimerSource()
    timer.schedule(deadline: .now() + delay)
    timer.setEventHandler {
        closure()
    }
    //resume忘れるとエラーが出る!!
    timer.resume()
    return timer
}
 
class Playground_ConnectableOps {
     
    let bag = DisposeBag()
    var timer:DispatchSourceTimer?
    var timer2:DispatchSourceTimer?
    var timer3:DispatchSourceTimer?
     
    func withoutOperators() {
        print("withoutOperators ===")
         
        let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
         
        _ = interval
            .subscribe(onNext: { print("Subscription: 1, Event: \($0)") })
 
        timer = delay(3) {
            _ = interval
                .subscribe(onNext: { print("Subscription: 2, Event: \($0)") })
        }
         
        /*
         withoutOperators ===
         Subscription: 1, Event: 0
         Subscription: 1, Event: 1
         Subscription: 1, Event: 2
         Subscription: 1, Event: 3
         Subscription: 2, Event: 0
         Subscription: 1, Event: 4
         Subscription: 2, Event: 1
         Subscription: 1, Event: 5
         Subscription: 2, Event: 2
         Subscription: 1, Event: 6
         Subscription: 2, Event: 3
         */
    }
     
    func samplePublish() {
        print("pubish ===")
         
        let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
            .publish()
         
        _ = intSequence
            .subscribe(onNext: { print("subscription 1:, Event: \($0)")})
         
        
        timer2 = delay(2) {
            _ = intSequence
                .subscribe(onNext: { print("Subscription 2:, Event \($0)") })
        }
        timer = delay(4) { _ = intSequence.connect() }
        timer3 = delay(6) {
            _ = intSequence
                .subscribe(onNext: { print("Subscription 3:, Event \($0)")})
        }
         
        /*
         4秒後にconnect() されてからemit開始
          
         pubish ===
         subscription 1:, Event: 0
         Subscription 2:, Event 0
         subscription 1:, Event: 1
         Subscription 2:, Event 1
         Subscription 3:, Event 1
         subscription 1:, Event: 2
         Subscription 2:, Event 2
         Subscription 3:, Event 2
         subscription 1:, Event: 3
         Subscription 2:, Event 3
         Subscription 3:, Event 3
         subscription 1:, Event: 4
         Subscription 2:, Event 4
         Subscription 3:, Event 4
         */
    }
     
    func replay() {
        print("replay ===")
         
        let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
            .replay(1)
         
        _ = intSequence
            .subscribe(onNext: { print("subscription 1:, Event: \($0)")})
         
        timer = delay(2) { _ = intSequence.connect() }
        timer2 = delay(4) {
            _ = intSequence
                .subscribe(onNext: { print("Subscription 2:, Event \($0)") })
        }
         
        timer3 = delay(6) {
            _ = intSequence
                .subscribe(onNext: { print("Subscription 3:, Event \($0)")})
        }
         
        /*
         replay ===
         subscription 1:, Event: 0
         Subscription 2:, Event 0
         subscription 1:, Event: 1
         Subscription 2:, Event 1
         subscription 1:, Event: 2
         Subscription 2:, Event 2
         Subscription 3:, Event 2
         subscription 1:, Event: 3
         Subscription 2:, Event 3
         Subscription 3:, Event 3
         */
    }
}

Error Handling Operators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
enum TestError: Error {
    case test
}
 
class Playground_ErrorHandling {
    let bag = DisposeBag()
     
    func catchErrorJustReturn() {
        print("catchErrorJustReturn === ")
         
        let sequence = PublishSubject<String>()
         
        sequence
            .catchErrorJustReturn("a")
            .subscribe { print($0) }
            .disposed(by: bag)
         
        sequence.onNext("b")
        sequence.onNext("c")
        sequence.onNext("d")
        sequence.onError(TestError.test)
         
        /*
         errorになったら catchErrorJustReturn の引数をemitして終了
          
         catchErrorJustReturn ===
         next(b)
         next(c)
         next(d)
         next(a)
         completed
         */
    }
     
    func catchError() {
        print("catchError ===")
         
        let sequence = PublishSubject<String>()
        let recoverySequence = PublishSubject<String>()
         
        sequence
            .catchError {
                print("Error;", $0)
                return recoverySequence
            }
            .subscribe { print($0) }
            .disposed(by: bag)
         
        sequence.onNext("a")
        sequence.onNext("b")
        sequence.onNext("c")
        sequence.onError(TestError.test)
         
        recoverySequence.onNext("recovery")
         
        /*
         errorになったらhandlerを実行する。もしreturnしたら
         そのsequenceをemitする
          
         catchError ===
         next(a)
         next(b)
         next(c)
         Error; test
         next(recovery)
         */
    }
     
    func retry() {
        print("retry ===")
         
        var count = 1
         
        let sequence = Observable<String>.create { observer in
            observer.onNext("a")
            observer.onNext("b")
            observer.onNext("c")
             
            if count == 1 {
                observer.onError(TestError.test)
                print("Error encountered")
                count += 1
            }
             
            observer.onNext("d")
            observer.onNext("e")
            observer.onCompleted()
            return Disposables.create()
        }
         
        sequence
            .retry()
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         retry ===
         a
         b
         c
         Error encountered
         a
         b
         c
         d
         e
         */
    }
     
    func retry2(){
        print("retry2 ===")
         
        var count = 1
         
        let sequence = Observable<String>.create { observer in
            observer.onNext("a")
            observer.onNext("b")
            observer.onNext("c")
             
            if count < 3 {
                observer.onError(TestError.test)
                print("Error encountered. count: \(count)")
                count += 1
            }
             
            observer.onNext("d")
            observer.onNext("e")
            observer.onCompleted()
            return Disposables.create()
        }
         
        sequence
            .retry(4)
            .subscribe(onNext: { print($0) })
            .disposed(by: bag)
         
        /*
         retry2 ===
         a
         b
         c
         Error encountered. count: 1
         a
         b
         c
         Error encountered. count: 2
         a
         b
         c
         d
         e
         */
    }
}

Debugging Operators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Playground_DebuggingOperators {
    let bag = DisposeBag()
     
    func debug() {
        print("debug ===")
         
        var count = 1
         
        let sequence = Observable<String>.create { observer in
            observer.onNext("a")
            observer.onNext("b")
            observer.onNext("c")
             
            if count < 5 {
                observer.onError(TestError.test)
                print("Error encountered")
                count += 1
            }
             
            observer.onNext("d")
            observer.onNext("e")
            observer.onCompleted()
             
            return Disposables.create()
        }
         
        sequence
            .retry(1)
            .debug()
            .subscribe { print($0) }
            .disposed(by: bag)
 
        /*
         debug ===
         2019-01-29 19:26:00.410: Playground_DebuggingOperators.swift:41 (debug()) -> subscribed
         2019-01-29 19:26:00.418: Playground_DebuggingOperators.swift:41 (debug()) -> Event next(a)
         next(a)
         2019-01-29 19:26:00.418: Playground_DebuggingOperators.swift:41 (debug()) -> Event next(b)
         next(b)
         2019-01-29 19:26:00.418: Playground_DebuggingOperators.swift:41 (debug()) -> Event next(c)
         next(c)
         Error encountered
         2019-01-29 19:26:00.420: Playground_DebuggingOperators.swift:41 (debug()) -> Event error(test)
         error(test)
         2019-01-29 19:26:00.421: Playground_DebuggingOperators.swift:41 (debug()) -> isDisposed
         */
    }
}

おまけ Void

Observable<Void>って、どうやって値をemitするのかと思ったら Void() ってやればよいみたい

1
2
3
4
5
6
7
8
9
10
11
12
let sequence = Observable<Void>.create{ observer in
    observer.onNext(Void())
    observer.onCompleted()
    return Disposables.create()
}
let bag = DisposeBag()
sequence.subscribe{ print($0) }.disposed(by: bag)
 
/*
 next(())
 completed
 */
LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る