ぐーるらいふ

底辺。

【Unity】ソロだけど、Zenjectを使ってみたい。超初心者向け?

万年ソロプレイなぐーるです。よろしくお願いします。
また間が空いてしまいました。
なんていうか年末年始は問題がよく出たり、人が抜けたり人が増えたり
と運用をメインにしているとバタバタな期間だったりします。
2-3月は少し落ち着くといいなあ。(4月からはまたバタつく)

zenjectを使ってみたい

github.com


C#用のDI container。
オジサン的にはSpringとかseasorとかむかーし使ってたなぁなんて印象です。
個人的にこういうの結構好きでして、多人数開発になると「こうかはばつぐんだ!」っていう感じです。
とはいえ、個人で使う分には手に余るような部分が多く、手を出しづらいのですよね。

重い腰を上げる

まずは「zenject」で検索。

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

ふむふむ、installerとcontextとbindかぁ。
え、bindするには必ずinstallerをアタッチしないとダメなのかな?
と思ったのだけど、公式のreadmeを見てみると、すごくシンプルでも動きそう?

やってみた手順

1. unityで適当なプロジェクトを作る
2. Asset Storeでzenjectを検索して、プロジェクトにインポートする
3. 上部メニューGameObject > Zenject > SceneContext を押下して、SceneContextを作成
4. uGUIで適当にテストするbuttonを作る

f:id:ghoul_life:20180122204841p:plain

4. 以下の適当スクリプトを作る(計3つ)
DIContainerに使いまわしたいオブジェクトをBindする。
そして使いたい所でResolveするだけ。

f:id:ghoul_life:20180122205822j:plain

Node.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// DIContainerにbindして色々な所で使いたいクラス
public class Node {
	Node(){
		Debug.Log("Node class New : " + this.GetHashCode());
	}

	public void print(string message)
	{
		Debug.Log("node print == " + message + " | hashCode == " + this.GetHashCode());
	}
}
Exec1.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Zenject;

public class Exec1 : MonoBehaviour {
	[Inject]
	DiContainer container;

	public void Bind(){
		// 以下の3つのbind typeがある。
		Debug.Log("bind");
		//container.Bind<Node>().AsSingle();
		//container.Bind<Node>().AsTransient();
		container.Bind<Node>().AsCached();
	}

	public void Resolve(){
		var node = container.Resolve<Node>();
		node.print("exec1");
	}

	public void UnBind(){
		Debug.Log("unbind");
		container.Unbind<Node>();
	}
}
Exec2.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Zenject;

// 使う所その2
public class Exec2 : MonoBehaviour {
	[Inject]
	DiContainer container;

	public void Resolve(){
		var node = container.Resolve<Node>();
		node.print("exec2");
	}
}

5. 上で作ったbuttonにイベントを割り当てる
6. 動かしてみる

結果

最小構成で簡単にbindして使う事が出来た。

containerにbindする時以下の3つを指定できる。
これを理解しておこう。

AsSingle()

f:id:ghoul_life:20180122210320p:plain

bind , unbindを繰り返してもnewは一度しか発生せず、resolveの結果は変わらなかった。
つまりunbindしてもzenject内にオブジェクトを保持していて、
再bind時にはそれが利用されているようだ。
ということはGCの対象にならず、アプリを終了するまで開放することが出来ないだろう。

AsTransient()

f:id:ghoul_life:20180122210500p:plain

resolveする度にnewをしている。
そのため、毎回別のオブジェクトとして扱われる。

AsCached()

f:id:ghoul_life:20180122210711p:plain

AsSingle()と挙動が似ている。unbind、再bindを行うとnewされるようだ。(newされる瞬間は最初のResolve時)
つまり、unbind時にはzenjectからも開放されているため、GCの対象になってくれる。
最も使いやすいのでは無いだろうか。迷ったらとりあえずコレで良さそう。

こんな挙動の違いを見ることが出来た。

終わりに

シンプルに使おうと思うとこんなに簡単なんですね。
個人開発でしかunityを使ったことが無いので、こういった開発補助ライブラリ
は余り使わなくてもいいのかもしれないけど、メモとして残しておく!

都内は大雪です。