Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
208
Help us understand the problem. What is going on with this article?
@jollyjoester

RxSwift触ってみた

More than 5 years have passed since last update.

先週メルカリのグループ会社ソウゾウがリリースした「アッテ」の開発の裏側を聞けるatte FeS【Go・Swift開発編】に行ってきました。

その際の発表資料がこちらで公開されており、その中でもSwiftとRxSwiftの内容を聞いてRxSwiftに興味を持ったので今更ですが入門してみました。

RxSwiftとは

ReactiveX(Reactive Extensions)のSwift実装です。他にもRxJavaやRxJSなど各言語や各プラットフォーム用のRxがあります。

ReacitveXというのは

ReactiveX is a library for composing asynchronous and event-based programs by using observable sequences.

らしいです。

observableのシークエンスを使って非同期でイベントベースのプログラムを実現するためのライブラリ。

という感じでしょうか?

このobservableというのがキモらしいのですがよくわからないので実際に動かしてから勉強しようと思いました。

導入してみる

RxSwiftのinstllationを見るとCocoaPodsやCarthageで導入できるようです。今回はCocoaPodsで導入してみます。

まずRxSwiftSampleというプロジェクトを作成します。

そしてPodfileに下記のように記述。

Podfile
use_frameworks!

target 'RxSwiftSample' do
    pod 'RxSwift',    '~> 2.0'
    pod 'RxCocoa',    '~> 2.0'
end

# RxTests and RxBlocking have most sense in the context of unit/integration tests
target 'RxSwiftSampleTest' do
    pod 'RxBlocking', '~> 2.0'
    pod 'RxTests',    '~> 2.0'
end

下記のコマンドを実行します。

$ pod install
...
Installing RxBlocking (2.4)
Installing RxCocoa (2.4)
Installing RxSwift (2.4)
Installing RxTests (2.4)
...

ということで2.4が入ったようです。

その他の環境は下記で試しています。

Xcode
Version 7.3 (7D175)

pod --version
0.39.0

RxSwiftを使って実装してみる

テキストフィールドの変更をラベルに自動反映

さっそくSwiftとRxSwiftのP37にある「テキストフィールドの変更をラベルに自動反映」を試してみます。

Rxを使わない実装と比較するためにラベルとテキストフィールドを2つずつ配置します。
左側をRxを使った実装(label1, textField1)、右側を既存実装(label2, textField2)としてみます。

Screen_Shot_2016-04-26_at_02_12_47.png

とりあえずRxSwiftを使った実装は下記。

ViewController.swift
import UIKit
import RxSwift      // 1. RxSwiftインポート
import RxCocoa      // 2. RxCocoaインポート

let disposeBag = DisposeBag()   // 3. unsubscribeに必要なもの?

class ViewController: UIViewController {

    // for Rx impl
    @IBOutlet weak var label1: UILabel!
    @IBOutlet weak var textField1: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        textField1.rx_text                  // 4. rx_textは後述
            .map {"「\($0)」"}                // 5. 変更があった要素に「」つけて
            .bindTo(label1.rx_text)         // 6. labelに反映
            .addDisposableTo(disposeBag)    // 7. 不要になったらunsubscribe 
    }

    // ...

}

おお、これだけでテキストフィールドの変更がさくさくラベルに反映される!楽しい。

rx_textとは?

さて、突然textField1にrx_textというプロパティができていますが、
見てみるとRxCocoaが下記のようなextensionでrx_textを定義していました。

UITextField+Rx.swift
extension UITextField {
    /**
    Reactive wrapper for `text` property.
    */
    public var rx_text: ControlProperty<String> {
        return UIControl.rx_value(
            self,
            getter: { textField in
                textField.text ?? ""
            }, setter: { textField, value in
                textField.text = value
            }
        )
    }
}

さらに掘っていくとrx_textObservableTypeというprotocolに適合していました。
こいつがobservable!(まだ全然わかってないけど)

そしてそのrx_textmap, bindTo, addDisposableToといろいろ操作をしていくようです。

詳しくはまた今度見ようと思いますが、

  • obsevableを一個一個処理して(map)
  • observerに紐付けて(bindTo)
  • いらなくなったらremoveObserver(addDisposableTo)

と想像。

既存実装で同じ動きを実装してみる

比較のためRxSwiftを使わないで実装してみます。
いくつか実装方法はあると思いますが、テキストが変更されたときに通知されるUITextFieldTextDidChangeNotificationを使って実装してみます。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    // for existing impl
    @IBOutlet weak var label2: UILabel!
    @IBOutlet weak var textField2: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        // for existing impl
        label2.text = "「」"
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UITextInputDelegate.textDidChange(_:)), name: UITextFieldTextDidChangeNotification, object: self.textField2)
    }

    // ...  

    func textDidChange(notification: NSNotification) {
        if let text = textField2.text {
            label2.text = "「\(text)」"
        }
    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}

これでも同じ動きは実装できましたが、テキストが変更されたときの処理やremoveObserverの処理を別メソッドとして離れた場所に実装することになるので対象のViewの数が増えるとどれがどの処理がわかりにくくなりそうです。

一方でRxSwiftを使うとすべてをviewDidLoadの1箇所に書けるので、Rxの流儀に慣れればすごくソースが読みやすくなる気がしました。

まとめ

とりあえずなんとなくどう動いているのかというのとRx素敵そうというイメージが掴めました。次はなぞのobservableに具体的にどんなことができるのか見ていこうと思います。

今回のソース
https://github.com/jollyjoester/RxSwiftSample

208
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
jollyjoester
iPhone & Android開発者。
mercari
フリマアプリ「メルカリ」を、グローバルで開発しています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
208
Help us understand the problem. What is going on with this article?