Unity 시스템.Weak Reference 사용

19047 단어 Unity

개요


Unity 시스템.Weak Reference 테스트를 사용합니다.
System.Weak Reference 예.Net4.5에서 시작합니다.
https://msdn.microsoft.com/ja-jp/library/gg712738(v=vs.110).aspx

컨디션


Unity5.5.2p4

결실


사용 가능합니다.
System.참조는 Weak Reference의 Target에 저장되어 있으며 모델은 System입니다.Object.
이 Unity Engine 입니다.Object에 대한 특수 null 검사가 처리되지 않았습니다.
System.Weak Reference의 IsAlive, Target 처리를 변경하면 를 사용할 수 있습니다.

테스트 코드


대략적인 절차는 다음과 같다.
  • 장면 1의 TestObject 1 대상을 통해 TestObject 2 대상을 동적 생성
  • 동적으로 생성된 개체를 캐시에 등록(Weak Reference에서 참조)
  • 장면 1의 단추를 사용하여 장면 2로 이동
  • 장면 2를 불러와 캐시를 지우기
  • Weak Reference의 캐시 클래스를 테스트합니다.
    MonoBehaviourCache.cs
    using UnityEngine;
    using UnityEngine.SceneManagement;
    using System.Collections.Generic;
    
    [DefaultExecutionOrder(int.MinValue)]
    public class MonoBehaviourCache : MonoBehaviour
    {
        class UnityWeakReference<T> : System.WeakReference where T : UnityEngine.Object
        {
            public UnityWeakReference(T target) : base(target) {}
    
            public override bool IsAlive
            {
                get
                {
                    // MEMO: UnityEngine.Objectのnullチェックが特殊なためキャストして調査する
                    UnityEngine.Object obj = Target as UnityEngine.Object;
                    return obj != null;
                }
            }
    
            public new T Target
            {
                get { return base.Target as T; }
                set { base.Target = value; }
            }
    
            public bool TryGetTarget(out T target)
            {
                target = base.Target as T;
                return target != null;
            }
        }
    
        static MonoBehaviourCache _instance;
    
        Dictionary<int, UnityWeakReference<MonoBehaviour>> _dictionary = new Dictionary<int, UnityWeakReference<MonoBehaviour>>();
    
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        static void CreateInstance()
        {
            Debug.LogFormat("MonoBehaviourCache.CreateInstance()");
            GameObject gameObject = new GameObject("MonoBehaviourCache");
            _instance = gameObject.AddComponent<MonoBehaviourCache>();
            DontDestroyOnLoad(gameObject);
    
            SceneManager.sceneUnloaded += SceneUnloaded;
        }
    
        private static void SceneUnloaded(Scene scene)
        {
            Debug.LogFormat("MonoBehaviourCache.SceneUnloaded() scene:{0}", scene.name);
    
            List<int> removeIds = new List<int>(_instance._dictionary.Count);
    
            foreach(var pair in _instance._dictionary)
            {
                if (pair.Value.Target == null)
                {
                    Debug.LogFormat("MonoBehaviourCache.SceneUnloaded() Unused object. InstanceID:{0}", pair.Key);
                    removeIds.Add(pair.Key);
                }
                else
                    Debug.LogFormat("MonoBehaviourCache.SceneUnloaded() Already used object. InstanceID:{0}, Type:{1}", pair.Key, pair.Value.Target.GetType());
            }
    
            foreach (int id in removeIds)
                _instance._dictionary.Remove(id);
        }
    
        static public bool Add(MonoBehaviour monoBehaviour)
        {
            if (monoBehaviour == null)
                return false;
    
            int id = monoBehaviour.GetInstanceID();
    
            if (_instance._dictionary.ContainsKey(id))
            {
                Debug.LogFormat("MonoBehaviourCache.Add() Already contains instance id of object. InstanceID:{0}", id);
                return false;
            }
    
            _instance._dictionary.Add(id, new UnityWeakReference<MonoBehaviour>(monoBehaviour));
            return true;
        }
    
        static public T Get<T>(int instanceId) where T : MonoBehaviour
        {
            UnityWeakReference<MonoBehaviour> weakReference;
    
            if (!_instance._dictionary.TryGetValue(instanceId, out weakReference))
            {
                Debug.LogWarningFormat("MonoBehaviourCache.Get() Not found element. instanceId:{0}", instanceId);
                return null;
            }
    
            return weakReference.Target as T;
        }
    }
    
    인스턴스를 생성할 때 TestObject 2 객체를 생성합니다.
    버튼을 누르면 장면 2로 이동합니다.
    TestObject1.cs
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class TestObject1 : MonoBehaviour
    {
        int _instanceId;
    
        private void Awake()
        {
            GameObject gameObject = new GameObject("TestObject2");
            TestObject2 testObject2 = gameObject.AddComponent<TestObject2>();
            _instanceId = testObject2.GetInstanceID();
            Debug.LogFormat("TestObject1.Awake() testObject2 id:{0}", _instanceId);
    
            MonoBehaviourCache.Add(testObject2);
            testObject2 = MonoBehaviourCache.Get<TestObject2>(_instanceId);
            Debug.LogFormat("TestObject1.Awake() testObject2:{0}", testObject2);
        }
    
        public void OnPressedButton()
        {
            SceneManager.LoadScene("Scene2");
        }
    
        private void OnDestroy()
        {
            Debug.LogFormat("TestObject1.OnDestroy()");
            TestObject2 testObject2 = MonoBehaviourCache.Get<TestObject2>(_instanceId);
            Debug.LogFormat("TestObject1.OnDestroy() testObject2:{0}", testObject2);
        }
    }
    
    헛되이 실현하다.
    TestObject2.cs
    using UnityEngine;
    
    public class TestObject2 : MonoBehaviour
    {
    }
    

    출력 로그

    MonoBehaviourCache.CreateInstance()
    TestObject1.Awake() testObject2 id:-53294
    TestObject1.Awake() testObject2:TestObject2 (My.TestObject2)
    TestObject1.OnDestroy()
    TestObject1.OnDestroy() testObject2:null
    MonoBehaviourCache.SceneUnloaded() scene:Scene1
    MonoBehaviourCache.SceneUnloaded() Unused object. InstanceID:-53294
    

    프로필에 대한 조사


    장면 1

    필드 2로 이동 후

    좋은 웹페이지 즐겨찾기