3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RxSwiftのexampleをコードで書く(その1)

Last updated at Posted at 2018-05-25

#はじめに
コードのみでRxSwiftのexampleを書き直しました
(レイアウトはsnapKitをつかっております)

exampleその1

TextFiledに数字を入れると、一番下のラベルに3つの値の合計が即座に計算されるexample
screenshot.png

環境構築

プロジェクトファイルを作る

名前は何でもいいですが今回の例ではRxSwift_for_codeとしてます

podfileの編集

$ vi Podfile

Podfileの中身
target 'RxSwift_for_code' doRxSwift_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になっているはず
これは、処理が終わった後は観測を辞める必要があるとのことでおまじないのようにつけている感覚
(いつかきちんと理解したら書きたい)

3
5
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
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?