You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

游戏中通过Plist保存加载关卡数据异常问题求助

解决Plist保存关卡数据后台丢失的问题

老哥,我看你遇到的问题是关卡完成时SavedLevel的level能正常加1,但切后台后数据没存住——这在iOS用Plist存本地数据时挺常见的,我帮你从几个核心点排查修复:

1. 先确认你读写的是同一个Plist文件!

很多人踩坑在:从Bundle里读了初始Plist,但写入时又误写到Bundle路径了——而Bundle是只读的,根本写不进去!正确的姿势是把Plist复制到Documents目录(可读写区域),之后所有读写都用这个路径:

// 获取Documents下的Plist路径
func getGameProgressPlistPath() -> String {
    let docsDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    return docsDir + "/GameProgress.plist"
}

// 首次启动时复制Bundle里的模板Plist到Documents
func copyTemplatePlistIfNeeded() {
    let targetPath = getGameProgressPlistPath()
    let fileManager = FileManager.default
    guard !fileManager.fileExists(atPath: targetPath) else { return }
    
    if let bundlePath = Bundle.main.path(forResource: "GameProgress", ofType: "plist") {
        try? fileManager.copyItem(atPath: bundlePath, toPath: targetPath)
    }
}

启动App时先调用copyTemplatePlistIfNeeded(),之后读写全用getGameProgressPlistPath()返回的路径,别碰Bundle里的原文件。

2. 后台触发保存的逻辑要做对

iOS 13+之后,AppDelegate的后台方法可能被SceneDelegate接管了,你得确保在App进入后台时主动调用保存方法,甚至要处理后台任务超时的情况:

如果是用AppDelegate(iOS 12及以下):

func applicationDidEnterBackground(_ application: UIApplication) {
    SavedLevel.shared.saveCurrentLevel()
}

如果是SceneDelegate(iOS 13+):

func sceneDidEnterBackground(_ scene: UIScene) {
    SavedLevel.shared.saveCurrentLevel()
}

另外,系统给后台的执行时间有限,要是你的保存逻辑耗时(虽然Plist写入很快),最好加个后台任务延长时间:

func saveCurrentLevel() {
    var bgTask: UIBackgroundTaskIdentifier = .invalid
    bgTask = UIApplication.shared.beginBackgroundTask(withName: "SaveLevelProgress") {
        UIApplication.shared.endBackgroundTask(bgTask)
        bgTask = .invalid
    }

    // 执行写入逻辑
    let plistPath = getGameProgressPlistPath()
    let progressDict = ["currentLevel": self.level]
    let writeSuccess = (progressDict as NSDictionary).write(toFile: plistPath, atomically: true)
    
    // 加个日志排查写入失败
    if !writeSuccess {
        print("😅 Plist写入失败,检查路径或权限!")
    }

    UIApplication.shared.endBackgroundTask(bgTask)
    bgTask = .invalid
}

3. 确保SavedLevel的模型和保存逻辑同步

检查你的SavedLevel单例里,保存时是不是真的用了最新的level值,还有初始化时有没有正确加载数据:

class SavedLevel {
    static let shared = SavedLevel()
    var level: Int = 1

    private init() {
        // 启动时加载已保存的关卡
        loadSavedLevel()
    }

    func loadSavedLevel() {
        let plistPath = getGameProgressPlistPath()
        if let progressDict = NSDictionary(contentsOfFile: plistPath) as? [String: Int] {
            self.level = progressDict["currentLevel"] ?? 1
        }
    }

    func saveCurrentLevel() {
        // 这里一定要用self.level的最新值
        let progressDict = ["currentLevel": self.level]
        _ = (progressDict as NSDictionary).write(toFile: getGameProgressPlistPath(), atomically: true)
    }

    // 关卡完成时调用这个方法
    func completeLevel() {
        self.level += 1
        // 最好完成后立即保存,别等后台
        saveCurrentLevel()
    }
}

4. 测试时别直接点Xcode的Stop按钮!

模拟器里直接点Stop会跳过后台生命周期方法,导致保存逻辑没执行。正确测试步骤:

  1. 按⇧⌘H让App进入后台
  2. 等个2-3秒,让后台保存逻辑执行完
  3. 再终止App或者重新启动,看数据是否留存

要是还是有问题,你可以手动去Documents目录看Plist文件的内容:

  • Xcode顶部菜单选Window > Devices and Simulators
  • 选中你的设备/模拟器,找到你的App,点Download Container
  • 解压容器后,在AppData/Documents里找到你的Plist,打开看看值是不是对的

内容的提问来源于stack exchange,提问作者Matthew Fowler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:20:39