0

all.I'm a beginner of c# and unity.I want to make an audio manager with the dictionary.But it occurs an error"NullReferenceException" with blew code.

 public Dictionary<string, AudioSource> AudioDictionary = new Dictionary<string, AudioSource>() ;
 private List<AudioSource> resAudioSource = new List<AudioSource>();
 private const string ResourcePath = "Audio/";

 private void Awake()
 {
     #region instance
     if (instance == null)
     {
         instance = this;
         DontDestroyOnLoad(gameObject);
     }
     else
     {
         Destroy(gameObject);
     }
     #endregion

     AudioClip[] resAudio = Resources.LoadAll<AudioClip>(ResourcePath);
     AudioSource temp;

     for (int audioNum = 0; audioNum < resAudio.Length; audioNum++)
     {
         temp = gameObject.AddComponent<AudioSource>();
         Debug.Log(resAudio[audioNum].name);
         AudioDictionary.Add(resAudio[audioNum].name, temp);
     }
 }

And it's OK after change like this.

public Dictionary<string, AudioSource> AudioDictionary;
private List<AudioSource> resAudioSource = new List<AudioSource>();
private const string ResourcePath = "Audio/";

private void Awake()
{
    #region instance
    if (instance == null)
    {
        instance = this;
        DontDestroyOnLoad(gameObject);
    }
    else
    {
        Destroy(gameObject);
    }
    #endregion

    AudioDictionary = new Dictionary<string, AudioSource>();//the change
    AudioClip[] resAudio = Resources.LoadAll<AudioClip>(ResourcePath);
    AudioSource temp;

    for (int audioNum = 0; audioNum < resAudio.Length; audioNum++)
    {
        temp = gameObject.AddComponent<AudioSource>();
        Debug.Log(resAudio[audioNum].name);
        AudioDictionary.Add(resAudio[audioNum].name, temp);
    }
}

I'm very puzzled why I can't initialized the dictionary directly, Anybody can explain it?

ZJN
  • 13
  • 2
  • 6
  • 1
    `AudioDictionary` is a public field so it is possible that by the time `Awake()` method is called, some other code either sets it to null or clears it. See what is accessing it and what it's doing to your the dictionary. – CodingYoshi Nov 04 '17 at 04:38
  • 1
    @GrantWinney I agree with you. That Post is overused. To ZJN, What's your Unity version? And which line of code are you getting that error on with the first code? – Programmer Nov 04 '17 at 05:42
  • I see potential problem in code-path instance!=null -> Destroy(gameObject)->continue initialisation. Perhaps return after destroy would be better. – Mikko Koivisto Nov 04 '17 at 06:31
  • I agree with @codingYoshi - unlisted code is changing your pulic mutable AudioDictionary. Suggest change AudioDictionary to private readonly as it seems public not needed. – StuartLC Nov 04 '17 at 09:02
  • @Programmer.My unity is 2017.2 and I use VS 2017.The error occurs in line "AudioDictionary.Add(resAudio[audioNum].name, temp);".The error is "NullReferenceException: Object reference not set to an instance of an object" – ZJN Nov 04 '17 at 17:23
  • @CodingYoshi.I think you are right.I change the dictionary to private, and the error not occur.And I guess the reason is the plugin-in of Odin-inspector. – ZJN Nov 04 '17 at 17:31
  • @CodingYoshi.I use it to show the condition of serialized.Maybe it accesses the dictionary at first.But I am not sure because I'm not good at querying this kind of error.Do you have a way to make sure of this? – ZJN Nov 04 '17 at 17:38
  • @MikkoKoivisto.Em, I might know the destroy() method will not destroy the game object immediately. I ignore the problem, thank you for your remind.I know in general the game object will destroy in the end of update() and before rendering.Do you know if I don't add the return, when does the game object destroy? – ZJN Nov 04 '17 at 17:47
  • @ZJN I don't know when the game object destroys. I have to rely on the documentation which states (as you said) that "Actual object destruction is always delayed until after the current Update loop, but will always be done before rendering." However, I could not reproduce the error behaviour in my tests (see my answer, which is not an actual answer:) – Mikko Koivisto Nov 04 '17 at 21:03

1 Answers1

0

I could not reproduce the above-mentioned behaviour with 2017.1.1f1 Editor test. I inserted mp3 file in Assets/Resources/test.mp3 file. Then I created an empty GameObject with Test script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

public Dictionary<string, AudioSource> AudioDictionary = new Dictionary<string, AudioSource>() ;
private List<AudioSource> resAudioSource = new List<AudioSource>();
private const string ResourcePath = "Audio/";

public static Test instance;

private void Awake()
{
    #region instance
    if (instance == null)
    {
        instance = this;
        DontDestroyOnLoad(gameObject);
    }
    else
    {
        Destroy(gameObject);
    }
    #endregion

    AudioClip[] resAudio = Resources.LoadAll<AudioClip>(ResourcePath);
    AudioSource temp;

    for (int audioNum = 0; audioNum < resAudio.Length; audioNum++)
    {
        temp = gameObject.AddComponent<AudioSource>();
        Debug.Log(resAudio[audioNum].name);
        AudioDictionary.Add(resAudio[audioNum].name, temp);
    }
}
}

When inserting breakpoint into the for loop, I could see that AudioDictionary was not null and test.mp3 was added into AudioDictionary.

Mikko Koivisto
  • 301
  • 2
  • 6
  • Thank you for your trail.Like what my talking above, the error may occur because of the Odin-inspector plugin.@CodingYoshi what he said maybe right. – ZJN Nov 05 '17 at 19:20