読者です 読者をやめる 読者になる 読者になる

【Unity】Zenjectで禅の心を手に入れる

 

Zenjectについて

github.com

 

導入を躊躇っていたものの、あるところから脅しがかかったので本格的に使い始めた

 

基本的な使い方などはこちらをご参考いただければわかるのではないかと思います

Unity3DのDIフレームワーク、Zenjectの紹介 | Aiming 開発者ブログ

 

今回はちょっと具体的な使い方を模索してみました。

 

何ができるのか

リポジトリのreadmeを読めばわかる

DI(Dependancy Injection)を行うためのライブラリで、すっごい簡単に言うと

 

newの引数とか、シングルトンで引っ張ってきてたオブジェクトを、登録しておいたオブジェクトの中から勝手に引っ張ってきて自動で参照を入れてくれるやつ

 

って認識でいいと思う、もちろんこれは機能のごく一部に過ぎない

他にもいろいろできる、公式読んで 

 

中身の話

Zenjectの基本は

 

  1. Containerにオブジェクトを登録
  2. Containerに登録したオブジェクトをインスタンス化(この時に引数などの参照が自動で持ってこられる)
  3. オブジェクトが作られたらごにょごにょする

 

になる

Containerは、登録されたオブジェクトが入ってるDictionaryみたいなもので

ここの中にオブジェクトが登録されていないと、参照を解決できない

また、自動で参照してくれるようにするためには、参照先のオブジェクトも登録してあげないといけない

 

つまり、こう

 

gist.github.com

 

これは全てにおいて適用されるので、まずBindを忘れないようにしよう。

 

使い方

まだ全てを把握できているわけではないので、状況別で

 

 

SingletonにしていたManagerを、Singletonにしない

(MonoBehaviour継承クラスに、参照を渡す方法)

 

Zenjectには、ZenjectBindingというコンポーネントが存在する

こいつは、登録したコンポーネントを勝手にContainerに登録してくれるすごいやつ

 

実際に使ってみるとこうなる

f:id:yutakaseda3216:20170417121301p:plain

 

Managerの中身は、普通のMonoBehaviour継承クラスになっている

使用する場合は、こう書く

 

gist.github.com

 

MonoBehaviour継承クラスの場合は、Injectアトリビュートを使用することで自動で参照が設定される

非継承の場合は、newで渡してあげる

 

これで、Managerは自動で使いたいところで使えるようになるので、ただのstatic参照のためだけにSingletonである必要がなくなる

もちろん、同一インスタンスが一つしかないことを保証するために使うのはあり

同一クラスは一つのみ生成し、あとはキャッシュを使う.AsSingle()というBind方法が存在する

  

同じことをしてる人がいたので、こちらも

qiita.com

余談ですが、torisoupさんはいつも勉強になる記事をあげてくださっているので定期購読をお勧めします

 

また、Manager以外にもZenjectBindingに登録さえすればなんでも使えます

Playerとかカメラとかを登録すると捗るかもね

 

 Pureクラスを好きなタイミングでBindしながら生成する

 

MonoBehaviourの参照を渡したりするPureクラスとか・・・

クラスがごちゃごちゃしがちな原因の一つだが、Zenjectを使用することで解決出来る

 

 

まずMonoBehaviour継承クラスで渡したいクラスをBindする

  • シーンに最初から直置きしてあればZenjectBindingを使用する
  • 動的に生成される場合は、Container.Bindを使用してContainerに登録する

 

動的生成する際に勘違いされがちだが

別にInstallerを使って記述しなくてもいい

 

DIContainerへのBindさえできればよく、さらに

DIContainerはBindされているので好きなクラスにInjectで引っ張ってこれる

好きなタイミングでBindすればいいと思う

 

 試しに、ボタンを押したらHogeをBindして生成するにはこうする

 

gist.github.com

 

GameManagerはBindInstallerか何かでBindしてあげる必要があるが

BindさえすればDIContainerを引っ張ってこれるのでこういう書き方ができる

 

Container.Resolve<Hoge>()はBindされているオブジェクトをインスタンス化してreturnするメソッド

他にも.TryResolve<T>()などのメソッドが用意されているので、動的バインドする基底クラスかヘルパーを作ることをお勧めする

 

Resolveについては公式を

https://github.com/modesttree/Zenject#dicontainer-methods-resolve

 

ちなみに、BindされたPureクラスは明示的にUnBindしない限り参照を握られ続けるため破棄されない

Disposeメソッドなどを使い、破棄するタイミングでContainer.UnBind<Hoge>()を呼んであげよう

 

(これって非推奨だったりするのかな、知っている人がいたら教えてください)

その他

.FromNew

.FromMethodsとかは紹介したかったのですが、長くなりそうなのでまとめたときにでも

 

DIContainer.Inject

DiContainer.Instantiate

は今試してます。追記予定。

 

処理速度とかの測定はしてないんだけど、Bindは結構重いらしい

まあそうだろうねって感じだけど、これも測らないといけないね

 

終わり

禅の心強いわー