トップ > 【Unity】オブジェクトを安全に破棄する方法を紹介します!
更新日 2024/3/26

【Unity】オブジェクトを安全に破棄する方法を紹介します!

UnityEngine.ObjectはObject.Destroy関数で破棄することができます。このページではUnityオブジェクトを安全に破棄する方法を考察します。

destroy object thumbnail

安全にスクリプトを書くコツは何かあるのかな?

初めての方にも分かりやすく簡単に解説しますね。

一般的な解放処理

安全なオブジェクトの解放処理は昔から考えられてきました。インスタンスをnullチェックして解放し、その後nullを代入することで多重開放されることを防ぎます。コードに落とすと以下のような感じになります。

object obj;

if(obj != null)
{
delete obj;
obj = null;
}

言語問わず昔からある手法だね!

この考え方をベースにUnityEngine.Objectを安全に破棄する関数を作ってみましょう。

Unityオブジェクトの安全な破棄

Unityでオブジェクトを破棄するにはObject.Destroy関数を利用します。先ほど説明した安全な破棄方法でDestroySafe関数を実装してみましょう。

void DestroySafe(Object obj, float t = 0)
{
if(obj != null)
{
Object.Destroy(obj, t);
obj = null;
}
}

ここで引数で渡されたobjはいわゆる値渡しで元のインスタンスがnullに設定されることはありません。
objを参照渡しにするためにrefキーワードを使います。

void DestroySafe(ref Object obj, float t = 0)
{
if(obj != null)
{
Object.Destroy(obj, t);
obj = null;
}
}

これで完成のように思えますがref引数は厳格な型を要求しますので派生クラスのインスタンスは参照渡しできません。次のようなケースでエラーになります。

Texture2D texture = new Texture2D(1, 1); // Objectを継承してるTexture2D
DestroySafe(ref texture); // コンパイルエラー
エラー CS1503 引数 1: は 'ref UnityEngine.Texture2D' から 'ref UnityEngine.Object' へ変換することはできません

このエラーに対応するためにテンプレートを使ってUnityEngine.Objectを継承している全てのクラスを対象にしましょう。

void DestroySafe<T>(ref T obj, float t = 0) where T : Object
{
if (obj != null)
{
Object.Destroy(obj, t);
obj = null;
}
}

これでUnityEngine.Objectを継承している全てのクラスに対応できました。
使い方は以下の通りです。

DestroySafe(ref obj);

シンプルに一行で使えていい感じだね!

Unityエディター拡張に対応する

Unityエディターでの編集時(エディットモード)の時はDestroyの代わりにDestroyImmediateを呼ぶように警告されます。

Destroy may not be called from edit mode! Use DestroyImmediate instead.

エディットモードかどうかを判断するにはUNITY_EDITORマクロとApplication.isPlayingで判断できます。Unityエディターで編集中で実行中でないときにDestroyImmediateを呼ぶようにします。これらを踏まえてエディターに対応したDestroySafe関数は以下のようになります。

void DestroySafe<T>(ref T obj, float t = 0) where T : Object
{
if (obj != null)
{
#if UNITY_EDITOR
if (Application.isPlaying)
{
Object.Destroy(obj, t);
}
else
{
Object.DestroyImmediate(obj);
}
#else
Object.Destroy(obj, t);
#endif
obj = null;
}
}

以上で完成になります。ソースコードはGitHubにアップしてありますのでご利用下さい。

code-examples/unity/ObjectUtility.cs

使用例

Object obj = ...;
ObjectUtility.DestroySafe(ref obj);

どのような場面でもオブジェクトを安全に破棄する関数ができましたね。

まとめ

今回の記事のまとめだよ!

1.nullチェックしてオブジェクトを安全に破棄しよう!
2.エディットモード時はDestroyImmediateを使おう!

安全第一にね!

しつこいくらい安全にコーディングすることでバグを減らすことができますよ。

関連ページ

こちらのページも合わせてご覧下さい

screenshot
【Unity】ゲームビューのスクリーンショットを撮る方法を紹介します!2024/2/26
resident_object
【Unity】ゲームオブジェクトを常駐化させるための方法を紹介します!2024/3/1
singleton
【Unity】シングルトンパターンを実装する方法を紹介します!2024/3/1
resource
【Unity】スクリプトからテクスチャーなどのリソースを読み込む様々な方法を紹介します!2024/2/9
event_init
【Unity】MonoBehaviourの初期化イベントについて考察します!2024/2/12

Copyright ©2022 - 2024 うにぉらぼ