ScriptableObject的Awake()修改内容需重启Unity才显示于Inspector,求解决
问题分析与解决办法
根本原因
你遇到的问题核心在于ScriptableObject的Awake()方法在编辑模式下的执行时机与Unity编辑器序列化流程冲突。当你通过AssetMenu创建新实例时,Unity正处于资产初始化/导入阶段,此时在Awake()中修改列表并调用EditorUtility.SetDirty(),编辑器的序列化系统可能无法正确记录这些变更。当你点击Inspector或按下回车时,编辑器会刷新内存中的资产状态,导致未被正确序列化的列表被重置为空。而重启Unity时,资产会从磁盘重新加载,此时之前的变更才会被读取出来。
另外,EditorUtility.SetDirty()在新版Unity中已被弃用,直接调用AssetDatabase.SaveAssets()会干扰资产导入流程,引发"restrictions during asset importing"错误。
解决方案
1. 移除Awake()中的初始化逻辑,改用自定义资产创建方法
避免在Awake()中修改ScriptableObject数据,转而通过自定义菜单方法显式初始化资产,确保变更被编辑器正确记录。
2. 使用Undo.RecordObject替代EditorUtility.SetDirty
Undo.RecordObject是Unity推荐的编辑器变更记录方式,能正确通知序列化系统资产已修改,保证变更持久化。
3. 避免立即调用AssetDatabase.SaveAssets()
Unity会自动处理资产保存,仅在资产创建完成后调用一次即可,避免干扰导入流程。
代码示例
修改后的MySO类
using UnityEngine; using System.Collections.Generic; [CreateAssetMenu(fileName = "New MySO", menuName = "Custom/MySO")] public class MySO : ScriptableObject { public List<SomeOtherClass> someOtherClassList = new List<SomeOtherClass>(); // 移除Awake()中的初始化代码 // void Awake() { ... } // 专门的列表初始化方法 public void InitializeList() { // 添加你的SomeOtherClass实例 someOtherClassList.Add(new SomeOtherClass()); someOtherClassList.Add(new SomeOtherClass()); // 可继续添加更多实例 } } [System.Serializable] public class SomeOtherClass { // 你的可序列化字段 public int exampleValue; }
自定义编辑器创建脚本
using UnityEditor; using UnityEngine; public static class MySOCreator { [MenuItem("Custom/Create MySO with Initialized List")] public static void CreateMySO() { // 创建MySO实例 MySO newSO = ScriptableObject.CreateInstance<MySO>(); // 记录对象变更(替代SetDirty) Undo.RecordObject(newSO, "Initialize MySO List"); // 初始化列表 newSO.InitializeList(); // 生成唯一资产路径并创建资产文件 string assetPath = AssetDatabase.GenerateUniqueAssetPath("Assets/New MySO.asset"); AssetDatabase.CreateAsset(newSO, assetPath); // 安全保存资产数据库 AssetDatabase.SaveAssets(); // 在Project窗口定位到新创建的资产 Selection.activeObject = newSO; EditorGUIUtility.PingObject(newSO); } }
额外说明
- 通过
Custom/Create MySO with Initialized List菜单创建资产,列表会被正确初始化并持久化,不会出现点击后清空的问题。 - 若仍需保留Awake()初始化,可添加编辑模式判断与空列表检查(但不推荐,可靠性不如自定义创建方法):
void Awake() { if (Application.isEditor && !EditorApplication.isPlaying) { if (someOtherClassList == null || someOtherClassList.Count == 0) { someOtherClassList.Add(new SomeOtherClass()); Undo.RecordObject(this, "Initialize List"); } } }
内容的提问来源于stack exchange,提问作者Gabriel Balassa Turu
相关产品推荐
相关产品推荐

