RxSwiftのシンプルな説明
Swiftで簡単なアプリを写経するのは簡単なのであるが、やはり実用的なアプリを作成するには、レスポンシブでないと役な立たない(お客さん受けしない)よねということで、RxSwift
を学んでみた。
正直、3日間くらい、泣きながら、挫けそうになりながら、禿げそうになりながら食らいついていた。
はっきりいって理解するのがキツイ。
■ 開発環境
OS : MacOS High Sierra Version 10.13.6
Xcode : Version 9.4.1
■ サンプリアプリ
ボタンを押すとカウントアップするだけのアプリ。
■ ソースコード解説
ViewController.swift
のコードを説明する。
まずは、必要なライブラリをimportする。ここでは、RxSwift
を利用する。
[objc]
import UIKit
import RxSwift
[/objc]
先に、ラベルとボタンを配置する。
StreatBoardでも良いのであるが、敢えてコードで記述。
[objc]
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)
}
[/objc]
次に、RxSwift
の肝であるクラスを作成する。
[objc]
class RxSwiftSample {
}
[/objc]
RxSwiftSample
クラスには、private宣言されたsubject
をPublishSubject<Int>()
でインスタンス化して保持しておく。それと、そのsubjectをObservableとして返すeventを定義する。
そして、実際の処理を外部から呼べる myFunc()
メソッドを定義する。その中で、onNext
とかいうイベントを発行する。
これが基本的な雛形という感じかな?
[objc]
class RxSwiftSample {
private let subject = PublishSubject<Int>()
var event : Observable<Int>{
return subject
}
func myFunc(){
// 処理
print("myFuncが呼ばれました。")
// イベント発行
subject.onNext(self.data)
}
}
[/objc]
次に、このRxSwiftSample
クラスの使い方なのであるが、ViewController
から利用できるように、RxSwiftSample
をモデルとしてmodel
で宣言しておく。また、後で利用するdisposeBag
も宣言しておく。
[objc]
private let model = RxSwiftSample()
private let disposeBag = DisposeBag()
[/objc]
上記を、ViewController
から利用する。
先ずは、順を追ってわかりやすく、ボタンに対して、countUp(_ sender: UIButton)
が呼ばれるように記述する。これは特に問題はないはず。
重要なのは、ここからmodel
のmyFunc()
を呼び出すことである。
[objc]
override func viewDidLoad() {
//ボタンへイベント登録
countUpBtn.addTarget(self, action: #selector(ViewController.countUp(_:)), for: UIControlEvents.touchUpInside)
}
@objc func countUp(_ sender: UIButton){
print("カウントアップ")
//Modelの関数呼び出し
model.myFunc()
}
[/objc]
ここから、理解が進むと思うが、model.myFunc()
で処理を行うと、事前に登録されているsubscribe
で通知される。そして、 subject.onNext(self.data)
で渡されたパラメータも、value で受け取れる。
[objc]
//Reactive処理
model.event.subscribe(
onNext: {value in
print("ここで通知")
countLbl.text = String(value)
})
.disposed(by: disposeBag)
[/objc]
これで、ようやく頭の中で処理シーケンスがつながった。
それでも理解できない場合は、私と同じように1日悩んで、print()
仕掛けて、処理を追ってみると良いと思う。
やはり、このようなフレームワークやデザインパターンの理解は正直キツイ。それでも、時間を掛けて手を動かすのが、ベストプラクティスだと思う。
その助けになればと祈る。情報がちょっと時代遅れ感はあるのだが・・・。
始めたのが遅いので仕方ない。w
■ 最後に
ここに記したコードは、自分がRxSwift
の構造を理解するために作成したコードです。間違い等がございましたらご指摘願います。
下記、全ソースコードです。
[objc]
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)
}
}
[/objc]
Lovly Swift!!!