はじめに
筆者はここ1年間、主にバックエンド構築にSpring Bootを利用してきました。
Spring Framework自体は2002年頃にリリースされたそうなのですが、Spring BootはSpringベースでのアプリ開発を楽にしてくれる新たな形で様々なSpringのFramework群を統合したものとのことです。
(Spring Bootでググると2〜3年前辺りからの記事が多い印象です。)
Springの特徴は何と言っても DI でしょう。
今回はそのSpringの代名詞とも言える DI をSwiftで扱ってみたいと思います。
DIとは
DIとは『Dependency Injection』の略語で、日本語だと依存性の注入と翻訳されたりします。
具体的に何者なのかと言うと、
- コンポーネント間の依存関係を排除するソフトウェアパターン (Wikipedia – 依存性の注入)
- これにより疎結合性が高まるので単体テストが書きやすい
というものです。
Springベースのアプリでは基本パターンとして利用しています。
詳しい説明は省きますが、
Spring起動時にBean
化したオブジェクトを@Autowired
アノテーションを利用することで、DIコンテナ経由で簡単に DI を利用することができます。
注意しておきたいこととして、
Bean
定義したクラスは@Autowired
アノテーションで呼び出される際、デフォルトでシングルトンパターンとして生成されたオブジェクトを呼び出しています。
SwiftでDIするには?
さて、そんなSpringの特徴的なDIですが、Swiftアプリで利用することはできるのでしょうか?
筆者が調べたところ、最も人気のあるSwift版DIライブラリとしてSwinjectというものがあるようです。
本日時点でGitHub上のスター数が1,432
となっており、なかなかの注目度かと思います。
しかも、下記のようにSwift3にも対応しているのが嬉しいですね!
1 2 3 4 5 6 7 |
|
実際にSwinject
を利用してSwiftでのDIを試してみたいと思います。
Swinjectの使い方
では早速使ってみましょう。
Swinjectのインストール
CocoaPodsでインストールするために下記のようにPodfile
を作成しましょう。
1 2 3 4 5 6 7 8 9 10 |
|
その後にpod install
を実行しましょう。
これでSwinject
の用意は完了です。
DIしたいクラスの定義
サンプルとしてDIしたいクラスを定義します。
具体的なクラスだけでなく プロトコル を定義しているのは、
後々、同じようなJavaProgrammer
クラスを作成したくなった際に便利だからです。
(ベースが同じで、拡張機能が必要になった際に、0から書き直す必要がなくなります。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
続いて、先程作成したEngineer
を参照するCompanyOwner
クラスを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
ここでSwiftProgrammer
クラスでなくEngineer
プロトコルを参照することで、CompanyOwner
クラス自体がSwiftProgrammer
クラスに依存することがなくなりました。
つまりJavaProgrammer
を雇いたいCompanyOwner
クラスが必要になった場合、作成するのはJavaProgrammer
クラスのみで良くなります。
これはこれでCompanyOwner
クラスに対して単体テストコードを書く時にSwiftProgrammer
クラスに依存せずに書くことができます。
DIコンテナへのクラスの登録
さて、DIしたいクラスが定義できたので、そのクラスをDIコンテナに登録します。
公式ページによるとSwinjectStoryboard
を利用する場合と利用しない場合の2種類の方法があるそうですが、今回は簡単に対応可能なSwinjectStoryboard
利用する方法で書いてみます。
サンプルとして、ViewController.swift
でDIコンテナ経由で呼び出したクラスを利用したいとします。
その場合、下記のように、ViewController.swift
にコンテナ定義を書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
順々に説明すると、
defaultContainer
にEngineer
指定でSwiftProgrammer(name: "Takahiro")
が呼び出されるように登録defaultContainer
にPerson
指定でCompanyOwner(humanResource: r.resolve(Engineer.self)!)
が呼び出されるように登録
※ 1でEngineer
指定でSwiftProgrammer(name: "Takahiro")
呼び出しをセットしているので、それが2のCompanyOwner
の引数にセットされます。defaultContainer
にDIコンテナ経由での呼び出し先と先ほどまで定義していたPerson
指定での呼び出し元を紐付け
となっています。
これにより、下記のようにViewController.swift
内でDIコンテナ経由でPerson
指定で想定した処理を呼び出すことができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
上記を見ると、ViewController
クラスの中でPerson
をインスタンス化している箇所はないことがわかると思います。
つまり、DIコンテナ経由でPerson
を呼び出せているわけですね。
まとめ
さて、Swinject
を利用してサンプルを書いてみた感想ですが…
正直、Spring Bootと比較すると、Swiftでは手動で書くべきところが多いと感じました。
また、様々なUIViewController
にまたがって利用する場合は記載箇所に一工夫必要なのかなとも思いました。
(毎回、全UIViewController
系のファイルにsetUp()
を書くわけにもいかないと思いますし…)
まだまだ未知数なところがあるので、継続して試してみたいところではあります。
と言ったところで本日はここまで。
参考: