SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

RxSwiftで一歩進んだiOSアプリ開発

RxSwiftでiOSアプリ開発~リアクティブプログラミングを導入する

RxSwiftで一歩進んだiOSアプリ開発 第1回

  • X ポスト
  • このエントリーをはてなブックマークに追加

RxSwiftを導入するメリット

 RxSwiftを導入するとどういった点が便利なのかを、コードの書き方を紹介しながら説明します。RxSwiftを使った具体的なコードの書き方は連載第2回以降で扱うとし、ここでは簡単な紹介にとどめます。

UIの操作時の処理を簡潔に記述する

 スマートフォンアプリでは、時間軸上で起こるイベントはUI上で起こる動作の検出と考えて差し支えありません。RxSwiftでUIの操作に応じた処理を宣言的に記述する例を2つあげます。RxSwiftの文法は第2回以降で説明するので、ここではRxSwift導入前/導入後のソースコードの比較のみを行います。

1)IBActionを利用する例

 ボタンを押した際の処理と通常のSwiftとRxSwiftの書き方で比較すると次の通りになります。

[リスト3]UIButtonViewController.swift
import UIKit

class UIButtonViewController: UIViewController {
	
    @IBAction func onPush(_ sender: Any) {
        print("ボタンを押しました!")
    }
#後略
[リスト4]UIButtonRxViewController.swift
class UIButtonRxViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    let disposeBag       = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        button.rx.tap.subscribe(onNext: { _ in
            print("ボタンを押しました!")
        }).disposed(by: disposeBag)
    }
#後略

 両方の処理を図にして比べると下図になります。

ボタン押下時の処理の比較
ボタン押下時の処理の比較

 通常のSwiftの書き方では、ソースコード内の@IBActionで定義した処理はそのまま画面上のボタンと結合します。これは画面上のUIと処理が1対1で強く結合され、例えば画面上のUIを少し変更する場合でも、@IBAction の処理を改めて定義し直すことと同じ意味です。UIと処理は分離できません。

 これに対してRxSwiftでは、画面上のUIと結合するのはソースコードのプロパティのみです。処理の部分は、UIには直接影響しないように記述できます。画面上のUIを変更する場合でも、ソースコードへの影響は少なくて済みます。UIと処理を分離して管理することが可能です。

2)delegateを利用する例

 次によく利用される、delegateを経由した、入力欄に関する動作の例をあげます。

[リスト5]UITextFieldViewController.swift
class UITextFieldViewController: UIViewController {
    @IBOutlet weak var textField1: UITextField!
    @IBOutlet weak var textField2: UITextField!
#中略

extension UITextFieldViewController : UITextFieldDelegate { // UITextFieldDelegate内で入力欄1と2の処理を定義
    func textFieldDidBeginEditing(_ textField: UITextField) {
        switch textField {
        case textField1:
            print("入力欄1で入力を開始しました")
        case textField2:
            print("入力欄2で入力を開始しました")
        default:
            break
        }
    }
}
[リスト6]UITextFieldRxViewController.swift
class UITextFieldRxViewController: UIViewController {

    @IBOutlet weak var textField1: UITextField!
    @IBOutlet weak var textField2: UITextField!
    let disposeBag       = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        textField1.rx.controlEvent([UIControlEvents.editingDidBegin])	// 入力欄1に対する処理を定義
            .asDriver().drive(onNext: { _ in
                print("入力欄1で入力を開始しました!")
            }).disposed(by: disposeBag)

        textField2.rx.controlEvent([UIControlEvents.editingDidEnd])	// 入力欄2に対する処理を定義
            .asDriver().drive(onNext: { _ in
                print("入力欄2で入力を終了しました!")
            }).disposed(by: disposeBag)
    }
#後略

 両方の処理を図にして比べると次のようになります。

入力欄を操作する時の処理の比較
入力欄を操作する時の処理の比較

 通常のSwiftの書き方では、UIに対応するdelegateのメソッドを呼び出すことで処理を行います。この場合は、UIViewControllerでdelegateを実装するため、処理が本来のビューコントローラーの部分と離れがちです。また複数の同じUIが存在する場合でも、呼び出されるdelegateのメソッドは1つなので、delegateのメソッド内でどのUIに対する処理かを分岐して記述する必要があります。

 RxSwiftを利用すると、各UIのすぐ後ろにイベント処理を記述できます。UI単位で処理を記述できるため、delegateを利用する場合と違って処理の中で各UI別に処理を分岐する作業も必要ありません。

 上記の例からわかる通り、RxSwiftを利用することでより簡潔に、よりインタラクティブに処理を記述できます。

アプリ全体の構造を統一したフォーマットで管理する

 前項のサンプルで確認した通り、RxSwiftを利用することで、イベント処理や非同期処理をより簡潔に記述できます。これをうまく利用してアプリ全体のプログラム構造を統一したフォーマットのクラスで整理することもできます。システム全体を整理する際には、Webアプリケーションでよく利用される、MVCモデルが採用されることが多いです。iOSアプリ開発においても、MVC的な構造を利用するケースはよく見られます。

iOSアプリ開発でのMVCモデルの例
iOSアプリ開発でのMVCモデルの例

 MVCモデルはWebアプリケーションの開発に最適化された構造です。スマートフォンアプリでは、ViewとControllerがWebアプリケーションより密接な関係にあり、どうしてもControllerの肥大化が避けられません。

 言い換えると、スマートフォンアプリの開発では、MVCモデル以上の構造が必要になります。MVCモデルに変わる構造の1つとして、MVVMモデルがあります。MVVMモデルでは、ViewとModelの間にViewModelという構造を挟むモデルです。iOSアプリ開発で適応されるMVVMモデルは、次のような構造をしています。

iOSアプリ開発でのMVVMモデルの例
iOSアプリ開発でのMVVMモデルの例

 各処理の概要は次の通りです。

  1. スマートフォンの画面上でUIの操作やセンサーの値の変化など、イベントの発生を検知
  2. ViewからViewModelへイベントで発生した処理の対応依頼を行う
  3. ViewModelからModelへオブジェクトの操作などの処理の対応依頼を行う
  4. Modelが処理を行い、その結果をViewModelへ渡す
  5. ViewModelからViewへデータなどを渡す
  6. Viewで画面上への処理を反映

 それぞれの役割を簡単にまとめると次の通りです。

MVVMモデルの構成要素の役割
名前 概要
Model オブジェクトに関する操作
ViewModel ModelとViewの橋渡し
View UIで発生するイベントの管理/画面上の表示

 View内部では、ソースコードであるビューコントローラーとStoryboardのビュー部分が存在します。この2つはMVVMモデルでは明確に区別されていませんが、画面上のイベントや表示を担うものだと考えてください。

 MVVMの各部分をクラスで分けることで、アプリ全体をすっきりとさせて一部のソースコードが肥大化することを防ぐことができます。さらにRxSwiftを採用すると、すべての過程でイベントから非同期処理の流れを同じように記述することができ、非常に楽にソースコードを管理できます。大規模なアプリをチームで開発する際には、RxSwiftとMVVMモデルを採用すると、開発者側で特別に規則を作らなくてもアプリ開発のすべての過程を統一したルールで進められるメリットがあります。

まとめ

 今回はRxSwiftを導入するメリットと手順について簡単に説明しました。今回あげたUI以外の処理でも、RxSwiftを利用することで処理を簡潔かつ統一したフォーマットで記述することができます。RxSwiftのGitHubのページにもさまざまなサンプルが用意されているので、ぜひとも確認してみてください。連載第2回からは、もう少し具体的にRxSwiftの使い方を説明します。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
RxSwiftで一歩進んだiOSアプリ開発連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 片渕 彼富(カタフチ カノトミ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/11000 2018/08/16 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング