#はじめに
コードのみでRxSwiftのexampleを書き直しました
(レイアウトはsnapKitをつかっております)
exampleその1
TextFiledに数字を入れると、一番下のラベルに3つの値の合計が即座に計算されるexample
環境構築
プロジェクトファイルを作る
名前は何でもいいですが今回の例ではRxSwift_for_code
としてます
podfileの編集
$ vi Podfile
Podfileの中身
target 'RxSwift_for_code' do
のRxSwift_for_code
をプロジェクトファイルで使った名前にしてください
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!
target 'RxSwift_for_code' do
pod 'RxSwift', '~> 4.0'
pod 'RxCocoa', '~> 4.0'
pod 'SnapKit', '~> 4.0.0'
end
Podfileに登録したライブラリをおとしてくる (bundlerでcocoapodを管理しているためpodのコマンドを使うときはbundle execを前につける必要がある)
$ pod install
このときに作られたRxSwift_for_code.xcworkspace
を起動する
ViewController.swift
を開いて下記コードをコピペでうごきます
コードの中身
ViewController.swiftのなかみ
import UIKit
import RxSwift
import RxCocoa
import SnapKit
class ViewController: UIViewController {
var disposeBag = DisposeBag()
var number1: UITextField = {
let textField = UITextField()
textField.borderStyle = .roundedRect
return textField
}()
var number2: UITextField = {
let textField = UITextField()
textField.borderStyle = .roundedRect
return textField
}()
var number3: UITextField = {
let textField = UITextField()
textField.borderStyle = .roundedRect
return textField
}()
var label: UILabel = {
let label = UILabel()
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.number1)
self.number1.snp.makeConstraints { (make) -> Void in
make.width.equalTo(200)
make.height.equalTo(50)
make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top).offset(100)
make.centerX.equalTo(self.view)
}
self.view.addSubview(self.number2)
self.number2.snp.makeConstraints { (make) -> Void in
make.width.equalTo(200)
make.height.equalTo(50)
make.top.equalTo(self.number1.snp.bottom)
make.centerX.equalTo(self.view)
}
self.view.addSubview(self.number3)
self.number3.snp.makeConstraints { (make) -> Void in
make.width.equalTo(200)
make.height.equalTo(50)
make.top.equalTo(self.number2.snp.bottom)
make.centerX.equalTo(self.view)
}
self.view.addSubview(self.label)
self.label.snp.makeConstraints { (make) -> Void in
make.width.equalTo(200)
make.height.equalTo(50)
make.top.equalTo(self.number3.snp.bottom)
make.centerX.equalTo(self.view)
}
//観測可能なシーケンスのいずれかが要素を生成するたびに、セレクタ関数を使用して、指定された観測可能なシーケンスを1つの観測可能なシーケンスにマージします。
//orEmpty:`String?`型のコントロールプロパティを `String`型のコントロールプロパティに変換します。
Observable.combineLatest(number1.rx.text.orEmpty,number2.rx.text.orEmpty,number3.rx.text.orEmpty) { textValue1, textValue2, textValue3 -> Int in
return (Int(textValue1) ?? 0) + (Int(textValue2) ?? 0) + (Int(textValue3) ?? 0)
}
//入ってきた値をStringに変換する関数
.map { $0.description}
//新しいサブスクリプションを作成し、オブザーバに要素を送信します。
.bind(to: label.rx.text)
.disposed(by: disposeBag)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
理解のための自分なりの解釈
Observableに連なっていくのは処理の一連の流れなのだと思う
CombineLatestという関数
この関数は観測する値(この例だったらUITextFiledのtextの値)を複数入れて一つのデータの流れにする関数なのだと思う
public static func combineLatest<O1, O2, O3>(_ source1: O1, _ source2: O2, _ source3: O3, resultSelector: @escaping (O1.E, O2.E, O3.E) throws -> Self.E) -> RxSwift.Observable<Self.E> where O1 : ObservableType, O2 : ObservableType, O3 : ObservableType
ちなみに上の関数の定義をみてみると第四引数であるresultSelectorはクロージャーを受け取る引数である。
一番最後の引数でクロージャーの場合、上の例のように外にはみ出して連なることができる
つまり第4引数はこれである
textValue1はO1.E、textValue2はO2.E、textValue3はO3.Eにあたり途中でString型はIntに変換されクロージャー内の処理が終わる(Self.E→Intになるんですね)
{ textValue1, textValue2, textValue3 -> Int in
return (Int(textValue1) ?? 0) + (Int(textValue2) ?? 0) + (Int(textValue3) ?? 0)
}
number1.rx.text.orEmptyのorEmpty
orEmpty:String?
型のコントロールプロパティを String
型のコントロールプロパティに変換します。
UITextFiledに入ってるのか入っていないのかわからない値であるためString?というのが前提条件だと思うのだが、このデータの流れに入る際はString型に変換してくれる便利な関数ということらしい
$0.description
直前のクロージャーの処理を抜けるとInt型のデータがながれてくる
map関数は流れたデータそれぞれに処理を行う関数である.
クロージャー内の引数は$0と表しても良いので、クロージャー内でIntに変換されたされた値(たとえば$0=14というような値)がはいってくる
$0.descriptionのようにdescriptionをつなげると、$0で入ってきた値をString型に変換してくれる
(例 14(Int)→"14"(String))
##.bind(to: label.rx.text)
最後にbind関数に入る
public func bind<O>(to observer: O) -> Disposable where O : ObserverType, O.E == Self.E?
引数はobserver型のなにかの型 返り値はDisposableで入ってくるデータと同じ型である必要がある またObserverTypeの要素をもつ型である必要がある
Stringに変換した値は、UILabelクラスのインスタンスであるlabelのtextに入れるということらしい
##.disposed(by: disposeBag)
最後に流れ着いた先の値の返り値は前の段階でDisposableになっているはず
これは、処理が終わった後は観測を辞める必要があるとのことでおまじないのようにつけている感覚
(いつかきちんと理解したら書きたい)