Apple 开发初学码农必看:一个 SwiftData 离奇古怪的问题(下)

概述

在列位头发茂盛小码农们的撸码生涯中,大概都会遇到各种千奇百怪的问题。它们有的是真的难,而有的仅是看起来很难,实际只是一些"赳赳武夫"。当我们真正洞悉它们的根本原因后,可能会哭笑不得。

而这篇故事中的问题无疑属于后者,貌似不寒而栗,实则仅一只"纸老虎"而已。

在本篇博文中,您将学到如下内容:

    1. 问题来了
    1. ChatGPT、Deepseek、豆包均"无一幸免"
    • 5.1 ChatGPT(4o)
    • 5.2 Deepseek
    • 5.3 豆包
    1. 回到起点:恍然大悟!?

相信学完本课后的宝子们,将会对 SwiftData 的基本知识有更加深入的理解和掌控。

那还等什么呢?让我们马上开始 SwiftData 爆锤"纸老虎"大冒险吧! Let's go!!!8-)


4. 问题来了

为了最大化利用 Xcode 项目代码丰富的上下文,我们决定在原有项目中新建一个 Playground 来施展拳脚。

在新建的 Playground 文件中,贴入如下代码:

swift 复制代码
import Foundation
import SwiftUI
import SwiftData
@testable import AppProjectName	// 可省略

let container = ModelContainer.preview
let context = container.mainContext

let settings = try SingletonSettings.getShared(context)
settings.idiomsPageCount = 20

let sharedSettings = try SingletonSettings.getShared(context)
print("count is \(sharedSettings.idiomsPageCount)")

然而,就是这样一段简单的不能再简单测试代码的运行结果竟会让我们"目瞪口呆":

从上图中可以看到,我们在把共享 settings 的 idiomsPageCount 设置为 20 后,再次尝试获取的共享 settings 竟然回退到了原始的值。并且从上面的代码中,我们嗅出了一丝不太妙的气味:我们实际是在不停反复重建本应单例的 SingletonSettings 共享对象!

从问题的表现来看,一般出现这种情况可能的原因不外乎有以下几种:

  • 使用了不同的 ModelContext 对象;
  • 没有将创建后的 SingletonSettings 实例插入到上下文中;
  • 创建 SingletonSettings 后没有保存;

但是,通过观察我们的实现可以确保上述情况都不存在。

如果大家回顾之前 SingletonSettings 的实现代码,会发现一切看起来都是那么的无懈可击。

那么,这到底是"肿么回事"呢?

5. ChatGPT、Deepseek、豆包均"无一幸免"

在揭晓最终那个出乎意料简单的答案之前,我们觉得有必要先让各大 AI 深度思考引擎来尝试解决一下这个问题。

5.1 ChatGPT(4o)

ChatGPT 给我们的解释有点让人摸不着头脑,看似说了很多但其实啥也没说:

可以肯定的是,这个解释和根本症结差了不止十万八千里。

5.2 Deepseek

我们再来看看 Deepseek 的表现:

这个回答就更离谱了,它所说的 3 个问题(UUID 比较方式、缺乏唯一约束、上下文未同步)和实际的原因不能说离题太远,也基本是毫不相干。

5.3 豆包

最后来看看豆包 AI 编程引擎的应对:

不出所料,豆包在这个问题上基本也是不知所云。

当然比较 UUID 字符串在这里可能会造成程序崩溃,但这并不是该问题的"罪魁祸首"。

在上面 3 个"能打的" AI 都惘然若失之后,我们又该何去何从呢?

6. 回到起点:恍然大悟!?

其实,这种问题都有一个基本的特征:看起来实现完美无瑕,仿佛是库克在和我们故意作对一样。

当出现这种"绝不可能出错"却事与愿违的情况,可能往往就是非常简单的地方我们没有考虑到。

这时,最优的调试策略是:

  • 把最新的 m4 max 笔记本从窗户扔出去;
  • 点一杯超大杯冰镇可乐 + 牛排细细品味;
  • 玩半个小时暗黑破坏神2重制版;
  • 眺望远处男生或女生宿舍 30 分钟(取决于你是程序猿还是程序媛);
  • 用"最小化隔离"方法创建一个小项目来重新测试;

在用 SwiftData 模版重新创建项目测试后发现,并不存在之前那个问题。

所以如果不是我们之前出现了幻觉,基本可以确定 SwiftData 本身的实现逻辑是没有任何错误滴,库克也无需为此背锅了。

仔细检查新旧项目的不同之处,我们立即察觉到:旧项目中 SingletonSettings 是后来添加的 Model 类,我们少做了一件非常简单且非常重要的事!那就是在模型容器中注册它!

回到我们 ModelContainer 的实现中,为其 schema 添加 SingletonSettings 类型:

swift 复制代码
extension ModelContainer {
    
    fileprivate static let schema = Schema([
        Idiom.self,
        IdiomManager.self,
        SingletonSettings.self,	// 之前少了这一句 T_T
    ])
    
    private static func create(memoryOnly: Bool = true) throws -> ModelContainer {
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: memoryOnly)

        return try ModelContainer(for: schema, configurations: [modelConfiguration])
    }
    
    static var shared = try! create(memoryOnly: false)
    
    static let preview = try! create()
    
    static var auto = ProcessInfo.processInfo.isRunningInPreview ? ModelContainer.preview : .shared
}

在上面的实现中,我们仅仅添加了一行代码,即在 ModelConfiguration 的配置(schema)中注册新建的 SingletonSettings 类型。

现在,再次运行测试代码,你会发现我们已经正确获取到了唯一的 SingletonSettings 单例对象,也成功修改了其 idiomsPageCount 属性,整个世界都变得清净了:

由此,我们得到了 SwiftData 框架中的一个重要特性:如果 Model 类没有在模型容器中注册,它的实例不会被正确创建和保存。

看到这,肯定有秃头小码农们会说:这么简单,我早就看出来了!

如果是这样,那么恭喜!你们真是"火眼金睛",对 SwiftData 的感觉已相当 Nice;如果没有看出来也没有所谓,毕竟有时人在钻牛角尖时是会六亲不认的。

总结

在本篇文章中,我们进一步深入剖析了这个 SwiftData 里"刁钻古怪"的问题,在各大 AI 引擎皆"全军覆没"后,我们人肉给出了问题最根本的原因和解决之道。

感谢观赏,再会啦!8-)

相关推荐
CoderJia程序员甲2 小时前
GitHub 热榜项目 - 日榜(2025-09-01)
ai·开源·github·ai编程·github热榜
IAM四十二10 小时前
用Trae做一个浏览器插件
llm·ai编程·trae
飞哥数智坊10 小时前
实测阿里 Qoder,但我还是失望了
人工智能·ai编程
SleepyZone19 小时前
使用 Async Generator 实现 Agent 流式输出与流程控制
javascript·agent·ai编程
Jooolin19 小时前
【C++】C++11出来之后,到目前为止官方都做了些什么更新?
数据结构·c++·ai编程
Jooolin20 小时前
【C++】C++11都有什么新特性?
c++·ai编程·编程语言
得帆云低代码21 小时前
2025企业数智化转型基建标配:没有AI网关的企业正在掉队
openai·ai编程
iOS阿玮21 小时前
苹果市场常见的处罚邮件,最低处罚基本上听劝稳过。
uni-app·app·apple
YungFan1 天前
iOS26适配指南之Liquid Glass App Icon
ios·swift
原生高钙1 天前
大模型的流式响应实现
前端·ai编程