RxSwiftのシンプルな説明


Swiftで簡単なアプリを写経するのは簡単なのであるが、やはり実用的なアプリを作成するには、レスポンシブでないと役な立たない(お客さん受けしない)よねということで、`RxSwift`を学んでみた。

正直、3日間くらい、泣きながら、挫けそうになりながら、禿げそうになりながら食らいついていた。

はっきりいって理解するのがキツイ。

## 開発環境
OS : MacOS High Sierra Version 10.13.6 
Xcode : Version 9.4.1


## サンプリアプリ
ボタンを押すとカウントアップするだけのアプリ。

![スクリーンショット 2018-08-09 14.11.12.png](https://qiita-image-store.s3.amazonaws.com/0/3184/7b9dac80-cd38-6546-bd3e-5a9b5fbf7e41.png "スクリーンショット 2018-08-09 14.11.12.png")


## ソースコード解説
`ViewController.swift`のコードを説明する。

まずは、必要なライブラリをimportする。ここでは、`RxSwift`を利用する。

```ViewController.swift
import UIKit
import RxSwift
```

先に、ラベルとボタンを配置する。
StoryBoardでも良いのであるが、敢えてコードで記述。

```ViewController.swift
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Label
        let countLbl = UILabel()
        countLbl.text = "0"
        countLbl.textAlignment = .center
        countLbl.textColor = UIColor.blue
        countLbl.frame = CGRect(x: (self.view.frame.width-110)/2, y: 150, width: 110, height: 21)

        // Button
        let countUpBtn = UIButton()
        countUpBtn.frame = CGRect(x: (self.view.frame.width-100)/2, y: 200, width: 100, height: 30)
        countUpBtn.layer.borderWidth = 1.0
        countUpBtn.layer.borderColor = UIColor.blue.cgColor
        countUpBtn.layer.cornerRadius = 5.0
        countUpBtn.setTitleColor(UIColor.blue, for: .normal)
        countUpBtn.setTitle("カウントUP", for: .normal)
        countUpBtn.addTarget(self, action: #selector(ViewController.countUp(_:)), for: UIControlEvents.touchUpInside)

        self.view.addSubview(countLbl)
        self.view.addSubview(countUpBtn)
}
```

次に、`RxSwift`の肝であるクラスを作成する。

```ViewController.swift
class RxSwiftSample {

}
```

`RxSwiftSample`クラスには、private宣言された`subject`を`PublishSubject<Int>()`でインスタンス化して保持しておく。それと、そのsubjectをObservableとして返すeventを定義する。
そして、実際の処理を外部から呼べる `myFunc()`メソッドを定義する。その中で、`onNext`とかいうイベントを発行する。

これが基本的な雛形という感じかな？

```ViewController.swift
class RxSwiftSample {
    private let subject = PublishSubject<Int>()

    var event : Observable<Int>{
        return subject
    }
    
    func myFunc(){
        // 処理
        print("myFuncが呼ばれました。")
        // イベント発行
        subject.onNext(self.data)
    }
}
```

次に、この`RxSwiftSample`クラスの使い方なのであるが、`ViewController`から利用できるように、`RxSwiftSample`をモデルとして`model`で宣言しておく。また、後で利用する`disposeBag`も宣言しておく。

```ViewController.swift
private let model = RxSwiftSample()
private let disposeBag = DisposeBag()
```

上記を、`ViewController`から利用する。
先ずは、順を追ってわかりやすく、ボタンに対して、`countUp(_ sender: UIButton)`が呼ばれるように記述する。これは特に問題はないはず。
重要なのは、ここから`model`の`myFunc()`を呼び出すことである。

```ViewController.swift
    override func viewDidLoad() {
     //ボタンへイベント登録    
        countUpBtn.addTarget(self, action: #selector(ViewController.countUp(_:)), for: UIControlEvents.touchUpInside)
    }

    @objc func countUp(_ sender: UIButton){
        print("カウントアップ")    
        //Modelの関数呼び出し
        model.myFunc()
    }

```

ここから、理解が進むと思うが、`model.myFunc()`で処理を行うと、事前に登録されている`subscribe`で通知される。そして、 `subject.onNext(self.data)`で渡されたパラメータも、value で受け取れる。

```ViewController.swift
        //Reactive処理
        model.event.subscribe(
                onNext: {value in
                    print("ここで通知")                
                    countLbl.text = String(value)
                })
                .disposed(by: disposeBag)

```

これで、ようやく頭の中で処理シーケンスがつながった。
それでも理解できない場合は、私と同じように1日悩んで、`print()`仕掛けて、処理を追ってみると良いと思う。

やはり、このようなフレームワークやデザインパターンの理解は正直キツイ。それでも、時間を掛けて手を動かすのが、ベストプラクティスだと思う。

その助けになればと祈る。情報がちょっと時代遅れ感はあるのだが・・・。
始めたのが遅いので仕方ない。w

## 最後に

ちなみに、`RxSwift`の何が嬉しいのかということだが、例えば、カウントが10以上になったら、ラベルとかボタンの色を赤に変えるとかが、一箇所に簡単に書けます。

```ViewController.swift
        //Reactive処理
        model.event.subscribe(
                onNext: {value in
                    countLbl.text = String(value)
                    //
                    if(value > 10) {
                        countLbl.backgroundColor = UIColor.red
                    }
                })
                .disposed(by: disposeBag)

```

なかなかメリットが多そうです。

ここに記したコードは、自分が`RxSwift`の構造を理解するために作成したコードです。間違い等がございましたらご指摘願います。


下記、全ソースコードです。

```ViewController.swift
import UIKit
import RxSwift


private let model = RxSwiftSample()
private let disposeBag = DisposeBag()

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Label
        let countLbl = UILabel()
        countLbl.text = "0"
        countLbl.textAlignment = .center
        countLbl.textColor = UIColor.blue
        countLbl.frame = CGRect(x: (self.view.frame.width-110)/2, y: 150, width: 110, height: 21)

        // Button
        let countUpBtn = UIButton()
        countUpBtn.frame = CGRect(x: (self.view.frame.width-100)/2, y: 200, width: 100, height: 30)
        countUpBtn.layer.borderWidth = 1.0
        countUpBtn.layer.borderColor = UIColor.blue.cgColor
        countUpBtn.layer.cornerRadius = 5.0
        countUpBtn.setTitleColor(UIColor.blue, for: .normal)
        countUpBtn.setTitle("カウントUP", for: .normal)
        countUpBtn.addTarget(self, action: #selector(ViewController.countUp(_:)), for: UIControlEvents.touchUpInside)

        self.view.addSubview(countLbl)
        self.view.addSubview(countUpBtn)

        //Reactive処理
        model.event.subscribe(
                onNext: {value in
                    countLbl.text = String(value)
                })
                .disposed(by: disposeBag)
    }

    @objc func countUp(_ sender: UIButton){
        //Modelの関数呼び出し
        model.myFunc()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

class RxSwiftSample {
    private let subject = PublishSubject<Int>()
    private var data = 0

    var event : Observable<Int>{
        return subject
    }

    func myFunc(){
        // 処理
        data = data + 1

        // イベント発行
        subject.onNext(self.data)
    }
}
```

***Lovly Swift!!!***