v2.0.4 是一个纯 bug 修复版本,只做了一件事:修掉「应用适配」页删除已添加应用时面板必崩的问题。
问题现象
在「应用适配」页面,给任意应用点了最右侧的减号 → 面板立刻崩溃退出(macOS 崩溃报告:EXC_CRASH (SIGABRT),Abort trap: 6)。v2.0.3 上删除任意一个应用都会 100% 复现,不是偶发。
根因
Swift 运行时的「独占性检查」(Exclusivity Enforcement)拦下了同一次操作里的两次重叠访问:
ForEach($store.appOptions) { $entry in
AppOptionRow(entry: $entry) {
store.appOptions.removeAll { $0.bundleID == entry.bundleID } // ← 必崩
}
}removeAll(where:)对store.appOptions(@Observable类的存储属性)发起贯穿整个遍历的 modify(读写)访问;- 谓词里的
entry.bundleID来自ForEach($store.appOptions)派发的元素 Binding,读取时又对同一个属性发起一次 read 访问。
两次访问重叠 → swift_beginAccess 检测到冲突 → fatalError → abort()。崩溃栈第 7 帧的 key path getter for SettingsStore.availableSchemas/appOptions 与第 11–17 帧的 Binding.readValue() 完全对得上。
修复
SettingsStore新增removeAppOption(bundleID:),删除逻辑收敛到模型层;- 视图改为
store.removeAppOption(bundleID: entry.bundleID)——bundleID先求值成值类型再传参,读访问在调用前结束,读与写拆成两次不重叠的访问。
写盘侧无需改动:compileSquirrelPatch() 本来就会按 originalAppBundleIDs 把被删条目清成 null,删除后点「应用并重新部署」照常生效。
界面零改动,其余功能与 v2.0.3 完全一致。
安装
- 下载下方
Squirrel-Panel-2.0.4.dmg,挂载后把Squirrel Panel.app拖到Applications覆盖旧版; - 首次运行若被 Gatekeeper 拦截(本项目未做 Apple 公证),运行 DMG 内的
fix.command放行即可; - Homebrew 用户:
brew upgrade --cask squirrel-panel。
校验
swift build通过;单元测试 64 例,2 例失败为 v2.0.3 既有问题(判脏逻辑为异步重算、测试同步断言),与本次改动无关。- DMG sha256:
f3fe62bb07850cad1f6b2392b7a08eab9c86058c08de29f09ace79d75e4e17c2
Mr大狼 · 先求稳定,再求创新。