Instantiating objects only after a scene is loaded

I’m trying to spawn in objects into the scene from a save file. All the logic is done through my “GameManager” script which is a singleton and persists across both scenes. When transitioning from my main menu to the main level, I call

SceneManager.LoadScene("main_level");

However, this totally screws up my entire saving and loading methods. Apparently me methods get called before the scene loads, and hence the loadscene function resets my entire scene which throws a bunch of errors. How do I resolve this?

public void LoadGame()
    {
        SceneManager.LoadScene("main_level");

        string jsonData;
        if (newGame) // Start new game
        {
            var defaultPath = Application.streamingAssetsPath + "/Default/Default.json";
            if (File.Exists(defaultPath))
            {
                jsonData = File.ReadAllText(defaultPath);
                gameData = JsonUtility.FromJson<GameData>(jsonData);
            }
            else
            {
                Debug.LogError("Save file is missing at: " + defaultPath);
            }
        }
        else if (File.Exists(path + "/" + saveName))
        {
            jsonData = File.ReadAllText(path + "/" + saveName);
            gameData = JsonUtility.FromJson<GameData>(jsonData);
        }
        else
        {
            Debug.LogError("Save file is missing at: " + path + "/" + saveName);
        }
 
        /* Instantiate required objects */
 
        // Trees
        var treeParent = new GameObject("Trees");
        foreach (TreeSaveLoad.TreeData tree in gameData.trees)
        {
            var treeType = oakTree;
            switch (tree.type)
            {
                case (TreeSaveLoad.TreeType.Redwood):
                    treeType = redwoodTree;
                    break;
                case (TreeSaveLoad.TreeType.Birch):
                    treeType = birchTree;
                    break;
                case (TreeSaveLoad.TreeType.Beech):
                    treeType = beechTree;
                    break;
                case (TreeSaveLoad.TreeType.Pine):
                    treeType = pineTree;
                    break;
                case (TreeSaveLoad.TreeType.Oak):
                    treeType = oakTree;
                    break;
                case (TreeSaveLoad.TreeType.Maple):
                    treeType = mapleTree;
                    break;
                default:
                    Debug.LogError("Missing tree type.");
                    break;
            }
            var treeChild = Instantiate(treeType, tree.position, Quaternion.identity) as Transform;
            treeChild.SetParent(treeParent.transform, true);
            yield return null;
        }
 
        // Call load event
        if (EventManager.Instance.e_loadGame != null)
        {
            EventManager.Instance.e_loadGame.Invoke();
        }
 
        // Call last, after loading is finished
        if (EventManager.Instance.e_loadedGame != null)
        {
            EventManager.Instance.e_loadedGame.Invoke();
        }

Here is the full code for reference. I call all my methods and events AFTER the loadscene call. This script exists on the GameManager object which persists from the main menu to the new scene.

maybe check to see if scene is loaded first