1
votes

I have code that looks like this.

public static Dictionary<int, Action> functionsMap;
void Function()
{
    if (!isDictionaryInitialized)
    {
        functionsMap = new Dictionary<int, Action>();

        functionsMap.Add(1, () => StartCoroutine(Function1()));
        functionsMap.Add(1, () => StartCoroutine(Function2()));
    }
 }

void CheckForFunction()
{
    var r = currentFunctionNumber;

    if (functionsMap.TryGetValue(r, out currentAction)) { currentAction(); }
}

The code works fine when I start my program. However if I go to another scene and then return to it, I get this error.

"MissingReferenceException: The object of type 'ScriptName' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object."

The problem is I have never destroyed the object. Initially I didn't have bool isDictionaryInitialized and I defined the new Dictionary outside of the Function because I thought the error was related to my program trying to access a Dictionary that was deleted after the scene was closed. I get the same problem with or without the bool, and regardless of where I define the Dictionary.

What is causing this, and what is the reason so I can avoid making the same mistake?

Edit: This question was marked as duplicate, but the link I don't believe applies to my situation, or if it does I don't understand how. It says static objects are not reloaded on a scene change, and the Dictionary is defined as a static object. I also tried changing it to non-static and the result is the same.

I have dozens of gameobjects in my code and don't have this issue with any other object, so I assume the problem is related to how the dictionary object is defined. Is there a way to keep the Dictionary object from being destroyed on scene change? I don't have it as a game object in the scene, it's just defined in the code itself as a public static Dictionary. Could someone tell me what I need to do differently please and thank you?

2

2 Answers

1
votes

The problem might be caused by changing scenes because simply loading another scene would destroy all gameobject in the current scene.

According to Object.DontDestroyOnLoad.

The load of a new Scene destroys all current Scene objects.

To solve this, you can either use DontDestroyOnLoad function to mark the object you want to be kept before loading another scene, or using different way to load like LoadSceneMode.Additive without destroying the current scene.

0
votes

First you are adding two Actions to your Dictionary but both with the same key.

functionsMap.Add(1, () => StartCoroutine(Function1()));
functionsMap.Add(1, () => StartCoroutine(Function2()));

wouldn't this overwrite the first entry?


Than your general problem is:

While functionsMap is static the two actions / one action you added are non-static (StartCoroutine always requires an instance of MonoBehaviour to run on) and therefore only available for the according component! (You talked about an Update method so this has to be a MonoBehaviour attached to a GameObject in your first scene.)

Now if you change the Scene, the GameObject holding that component is probably destroyed if you are not using DontDestroyOnLoad

The result is that your static Dictionary stays intact and filled meaning the entry with key = 1 still exists but the Value namely the added non-static Action is no longer available.

To avoid that you should add

DontDestroyOnLoad(this.gameObject);

either in Awake or Start to prevent the GameObject holding the component and thereby holding the Action that belongs to the reference(s) in the entry in your Dictionary.