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

チリペヂィア

リンクフリー。サンプルコードなどは関連記事内でライセンスについて明示されない限り商用利用なども自由に行って構いませんが、自己責任でお願いします。またこれら日記内容の著作権自体は放棄していません。引用部分については引用元の権利に従ってください。

Editorクラスの寿命とか

まったりUnity記事再開。

あまり気にしたことが無かったんだけどUnityEditor.Editorでインスペクタ拡張する時のEditorクラスの寿命メモ。

GameObjectが選択される時:Editor.Awake()→Editor.OnEnable()
GameObjectが非選択になる時:Editor.OnDisable()→Editor.OnDestroy()

ちなみに、エディタでコードを変更するとUnityに戻った時に再コンパイルが自動で働きますが、既にGameObjectが選択中だった場合はAwake()とOnDestroy()が呼ばれません。

GameObject選択中再コンパイル:旧Editor.OnDisable()→新Editor.OnEnable()

で呼ばれます。つまりEditorの内部メンバーの初期化チェック/リソース解放はEnable/Disableに書くべき?というかもはやEditorでAwake/OnDestroyが呼ばれる意味が分からんですねコレ。

Start/Update

呼び出されません。

コンストラクタとデストラクタ

Editorは選択されるたびに新規生成され、Awake()前にコンストラクタが呼ばれます。つまり本当はこんな感じ。

GameObjectが選択される時:コンストラクタ→Awake()→OnEnable()
GameObjectが非選択になる時:OnDisable()→OnDestroy()→デストラクタ

が、コンストラクタではリソース生成も出来るようですが、デストラクタでのリソース解放、例えばDestroyImmediate()やRenderTexture.Release()は出来ません。エラーログが出ます。ゲームリソースの解放にはOnDisable()かOnDestroy()を使います。びみょい。

まとめ
  • Editor.OnEnable()で初期化チェックまたはOn~GUI()の度に毎回未初期化チェックする
  • Editor.OnDisable()で解放する。OnDestroy()でも可いやいや駄目じゃん。既フォーカス状態だとDestroy呼ばれないって自分で書いてるのに!プライベートリソース解放はOnDisable()で。
  • そもそもGameObjectのフォーカスが去るだけでEditorは丸ごと破棄されている。
staticでhide系に設定したEditor用のリソース

TextureとかMaterialとか、この手のリソースをEditorで静的保持している時、hideFlagを設定しないとシーンの保存で「リークしてる!」と怒られるので設定する事になると思います。これらは一体どういう扱いになっているのでしょうか。

まずエディタでコードを変更してUnityに戻ると再コンパイル/チェックが働きますが静的な変数はこれで全部nullに戻ってしまいます。変更して無いコードも含め全てです。

初期化はやり直せばいいだけですが古い静的リソースはどうすりゃ良いのか。hide状態だからFind系は使えないし旧Editorの静的フィールドはリセットされてしまいます…これ、おそらく多少の時差はあるかもしれませんがコッソリ削除してもらえるようです。

その時の実験が以下。

Editorからnew GameObject()して、hideAndDontSaveを設定して、OnDisable、OnDestroy、デストラクタでログを出力するMonoBehaviorをくっつけたんですが、再コンパイル契機でデストラクタだけログが出ました。GCタイミングの誤差があるのでいまいち明確なフローがつかめなかった感。

個人的には、静的オブジェクトの解放契機で複雑な事をするのは避けて、あとはUnityを信じるしかないかなぁというドンブリ感の強い結論に至りました。