Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

MVVMモデルをもっと便利に使ってみよう(前編)~入力/出力の変数に注目したMVVMモデルの設計

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

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2019/01/21 11:00

 連載第5回では、連載第4回で説明したMVVMモデルに対してもう少し踏み込んだ使い方を説明します。MVVMモデルのさらに踏み込んだ使い方や代表的なライブラリの使い方などを、前編と後編の2回に分けて説明します。今回は前編です。本連載では、これからRxSwiftを導入する方を対象読者としている関係上、RxSwift導入の初歩的な手順に関して主な説明を行います。そのため、便宜上クラス/メソッドの使い方が必ずしもRxSwiftの詳細な仕様通りでないこともあります。この点をご了承ください。

目次

はじめに

 連載第3~4回にかけてRxSwiftで処理を簡潔に記述できること、MVVMモデルを導入することにより機能を分離してクラスを管理できることなど、RxSwiftを利用した、基本的な画面の作成方法について主に紹介しました。今回はもう少し深くクラス分けについての考察を行い、もっと便利に利用できる方法などについて説明します。

MVVMモデルをもっとわかりやすく便利に利用する

 RxSwiftはRxが本来持っている性質とともに、Observer/Observable関連クラスも充実しています。このことは、言い換えるとアプリのどの場面でも同じ仕様のクラスが同じように使えてしまうという意味です。スマートフォンアプリの画面の表示には、必ずと言っていいほどタッチなどの動作を含めた入力と画面への表示としての出力を伴います。今回はこの入出力に注目してRxSwift/MVVMモデルの導入を考えてみます。

RxSwiftでの入出力の扱いについて

 連載第4回のサンプルのWikipedia検索アプリでは、検索ワード(searchWord: Variable<String>)と検索結果のリスト(items: Variable<[Result]>)はViewModel内で並列に定義されていました。2つの変数は一見したところでは、入力のための変数なのか、出力のための変数なのか区別はつきません。処理内容までソースコードを追って初めて、どういう目的の変数かわかります。

 RxSwiftは、書き方も容易で導入がしやすいライブラリです。その反面、さまざまな処理で利用できるため、似たような変数や処理が並んでしまうとかえって扱いに困ることもあります。

View-ViewModel間の変数
View-ViewModel間の変数

 その解決方法の1つとして、連載第4回で紹介した、Swiftのプロトコルの使い方を利用してRxSwiftの入出力をわかりやすくできる方法があります。

入出力変数をプロトコルで管理する

 入出力の変数を区別するために、ViewModelのクラスを作成する際に変数をプロトコルで分けて定義するという方法があります。ViewからViewModelのプロパティを利用する際には、入力なのか出力なのかが分かるようにする方法です。

 検索ワード(searchWord: Variable<String>)を入力、検索結果のリスト(items: Variable<[Result]>)を出力の変数としてプロトコルで定義する例は次のようになります。

[リスト1] 入出力の変数をプロトコルで定義する例
protocol ViewModelInputs {
    var searchWord: Variable<String?> { get }
}

protocol ViewModelOutputs {
    var items: Observable<[Img]> { get }
}

 2つの変数を { get } で読み込み専用と定義しているのは、「プロトコルを実装するクラスの初期化処理でデータバインドを行い、クラスの外からの参照を読み込みのみで行う」といった意味です。ただしSwiftの仕様では、プロトコルの実装の際に変数の読み込みができていれば、値を書き込み、「var」を「let」で扱うことも許可されています。この辺りのSwiftの仕様はあまり厳密ではありません。

 入出力のプロトコルを定義した後は、入出力のプロトコル自体にプロパティでアクセスできるプロトコルを次のように定義します。

[リスト2]入出力のプロトコルを管理するプロトコルの例
protocol ViewModelType {
    var inputs: ViewModelInputs { get }
    var outputs: ViewModelOutputs { get }
}

 上記のプロトコルを実装したクラスでは、入力用の検索ワードにはinputs.searchWordプロパティで、出力用の検索結果のリストにはoutputs.itemsプロパティでアクセスすることができます。具体的な例は次の通りです。

[リスト3]各プロトコルを実装したViewModelクラスの例
class ViewModel: ViewModelInputs, ViewModelOutputs, ViewModelType {
    // MARK: - Properties
    var inputs: ViewModelInputs { return self }
    var outputs: ViewModelOutputs { return self }

    // Input Sources
    let searchWord = Variable<String?>(nil)

    // Output Sources
    let items: Observable<[Result]>
# 後略

 クラスの外からは、inputs/outputsを変数の前につけることで入出力を区別して変数にアクセスできます。クラスの内部では、inputs/outputsをつけずに変数を利用することができます。このようにプロトコルを利用することで、入出力の変数を区別して扱うことができます。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

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

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

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

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

バックナンバー

連載:RxSwiftで一歩進んだiOSアプリ開発
All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5