前回はコンポーネントのキャッシュのお話をしました。
今回はキャッシュのタイミングについてもう少し。
タイミングの違いによる問題の発生で僕が経験したのは、
Instantiate()などで複製しそのままアクセスしようとすると、void Awake()やvoid Start()よりも早いタイミングでアクセスしてしまうので、NullReferenceExceptionを発生させてしまう、などです。
例えば、(スコープを無視してしまいますが)先ほどのTest.csでいくと、
public void Copy(){ var go = Instantiate(prefab); var test = go.GetComponent<Test>(); test.rectTransform.anchoredPosition = pos; }
というようなメソッドで外から複製後すぐアクセスといった形にしてしまうと、
void Copy()→ void Awake()→void Start()
と呼び出されるので、void Awake()やvoid Start()のタイミングでキャッシュしようとしている変数はvoid Copy()内のアクセス時点ではnullになっているわけです。
そういった意味でも可能であればInspector上で代入しておくか、プロパティやメソッドを用いて直接アクセスされないように保護しキャッシュしてやるほうが良いと思います。
話は変わりますが、前回のprivateなプロパティにキャッシュをする方法
using UnityEngine; using UnityEngine.UI; public class Test:MonoBehaviour{ RectTransform rectTransform{ get{ if(_rectTransform == null){ _rectTransform = GetComponent<RectTransform>(); } return _rectTransform; } } RectTransform _rectTransform; void Update(){ Debug.Log($"Position:{rectTransform.anchoredPosition}"); } }
がありましたが、この7-10行目は三項演算子(?:)を用いると、
return _rectTransform == null ? (_rectTransform = GetComponent<RectTransform>()) : _rectTransform;
と書け、null合体演算子(??)を用いると、
return _rectTransform ?? (_rectTransform = GetComponent<RectTransform>());
と書けます。
こちらのほうがきれいかな?