Unity使用Application.persistentDataPath读写编辑器正常iOS端报错如何解决
问题根因
- 首次启动App无缓存文件时,
RetrieveSavedModes方法未对savedModes做初始化兜底,直接返回null,后续访问.Count属性触发空引用 - 未处理反序列化失败场景:
as转换失败时storedModesFile为null,直接赋值给savedModes同样会触发空引用,iOS IL2CPP裁剪常导致自定义类序列化失败,Editor Mono环境无此问题 - 文件操作未正确释放资源,易触发之前遇到的IO路径冲突错误
- 硬编码路径分隔符存在跨平台兼容风险
修复方案
1. 修正读写逻辑,增加空兜底、资源自动释放、异常捕获
// 统一缓存路径,避免重复拼写错误 private readonly string SaveFilePath = Path.Combine(Application.persistentDataPath, "UserCustomModes.jl"); public void SaveModes() { // 空值兜底,避免序列化null if (savedModes == null) savedModes = new List<Mode>(); try { BinaryFormatter bf = new BinaryFormatter(); // using自动释放FileStream,无需手动Close using (FileStream file = File.Create(SaveFilePath)) { bf.Serialize(file, savedModes); } } catch (Exception e) { Debug.LogError($"Save failed: {e.Message}"); } } public List<Mode> RetrieveSavedModes() { // 先初始化兜底,避免任何异常场景返回null savedModes = new List<Mode>(); if (File.Exists(SaveFilePath)) { try { BinaryFormatter bf = new BinaryFormatter(); using (FileStream file = File.Open(SaveFilePath, FileMode.Open)) { var storedData = bf.Deserialize(file); // 校验反序列化结果是否合法 if (storedData is List<Mode> storedModesFile) { savedModes = storedModesFile; } } } catch (Exception e) { Debug.LogError($"Load failed: {e.Message}"); // 读取失败时删除损坏的缓存文件,避免后续持续报错 if (File.Exists(SaveFilePath)) File.Delete(SaveFilePath); } } return savedModes; }
2. 处理iOS IL2CPP裁剪问题
给自定义的Mode类添加序列化标记和防裁剪标记,避免IL2CPP裁剪掉序列化需要的元数据:
[Serializable] [UnityEngine.Scripting.Preserve] public class Mode { // 原有类成员不变 }
3. 可选校验逻辑
可在LoadSavedModes方法中增加空校验,进一步规避风险:
private void LoadSavedModes() { RemoveAllModeButtons(); Manager.savedModes = Manager.RetrieveSavedModes() ?? new List<Mode>(); Debug.Log("[UNITY] Retrieve Modes Count: " + Manager.savedModes.Count); PopulateModeView(); }
内容的提问来源于stack exchange,提问作者RobertH
相关产品推荐
相关产品推荐

