深入 Mac Sai 架构:MacClean、MacCleanKit、XPC 特权 Helper 与菜单栏 4 目标设计及 Swift 6 严格并发实践
【免费下载链接】MacSaiMac Sai: the open-source Mac cleaner, optimizer, and malware scanner. A free, Apple-notarized alternative to CleanMyMac, built with Swift 6 and SwiftUI.项目地址https://gitcode.com/gh_mirrors/mac/MacSai点击查看免费下载Mac Sai 是一款开源的 Mac 清理、优化与恶意软件扫描工具也是免费、无遥测、经 Apple 公证的 CleanMyMac 替代品使用 Swift 6 与 SwiftUI 构建。本文带你拆解它的工程架构4 个 SPM 目标如何分工、为什么刻意放弃传统 XPC 特权 Helper、菜单栏小组件如何实现常驻与多指标显示以及 Swift 6 严格并发在真实代码中的落地方式。先看全貌一个应用两种进程形态Mac Sai 由两个可执行程序组成主程序负责 17 个清理/防护/性能模块菜单栏程序则是一个轻量系统监视器。主程序入口是 MacCleanApp.swift刻意使用单个Window而非WindowGroup——配合 Info.plist 的LSMultipleInstancesProhibited保证菜单栏深链macclean://module/slug见 onOpenURL 处理打开应用时复用同一窗口永远不会出现两个主窗口。SPM 4 目标设计业务逻辑与 I/O 的边界整个仓库是一个 Swift PackagePackage.swift 声明了 3 个产品、4 个源码目标目标类型职责MacClean可执行主应用SwiftUI 视图、模块注册、权限服务MacCleanMenu可执行菜单栏 Login Item 应用实时统计与提示MacCleanKit库全部业务逻辑策略、解析、过滤、格式化零系统 I/O 依赖MacCleanTestSupport库测试夹具MockClock、二进制构造器等另有 MacCleanTests 与 MacCleanKitTests 两个测试目标合计 860 个测试用例。这种划分带来一个清晰约定见 菜单栏小组件持久化设计文档业务逻辑放 MacCleanKitI/O 留在 MacClean / MacCleanMenu。例如重复实例该退出哪一个这个看似琐碎的问题被抽成纯函数 MenuBarInstancePolicy——按launchDate最早、PID 最小做全序比较保证恰好一个存活、永不双方互杀这正是 issue #138 的根因而真正的exit(0)调用留在 MacCleanMenuApp.swift 这个薄 I/O 层。纯策略可以直接用 XCTest 穷举三进程竞态场景。为什么不用传统 XPC 特权 Helper大多数 Mac 清理软件会安装一个 root 级 XPC 特权 Helper 来执行系统维护。Mac Sai 做了不同的取舍原因写在 PrivilegedShellRunner.swift 的注释里密码提示体验macOS 对do shell script ... with administrator privileges的管理员密码缓存是按进程计算的约 5 分钟。如果每执行一次维护任务就 spawn 一个osascript子进程每个任务都会弹一次密码框issue #143。方案改用进程内NSAppleScript执行顺序执行的所有维护任务共享同一个凭据缓存只弹一次密码。命令拼装是纯字符串逻辑 MaintenanceShell.appleScriptSource每个参数用单引号 POSIX 转义可单测而不实际执行任何东西错误信息还会被 humanReadableError 剥掉1:92: execution error:前缀把真实的diskutil报错直接展示给用户。执行端是 actor MaintenanceExecutor——它同时持有需要管理员与普通Process两条路径actor 天然串行化所有任务避免并发弹出多个授权框。而菜单栏 Helper 走的是另一条路SMAppService.loginItem注册的Login Item嵌入在Mac Sai.app/Contents/Library/LoginItems/MacCleanMenu.app/由 MenuBarLauncher 管理注册/注销——注册本身是与backgroundtaskmanagementd的 XPC 往返但 Helper 本身不需要任何提升权限这也是安全设计的一部分能不用 root 就不用 root。菜单栏设计4 个指标、3 秒轮询、永不消失用户可选的 4 个实时指标菜单栏图标旁的数字由 MenuBarMetric 枚举决定磁盘可用空间、GPU 使用率、内存使用率、电池温度外加仅图标选项。rawValue 持久化在共享 defaults 中因此跨版本必须保持稳定——这类看似小的约束直接写进了类型注释里。轮询循环从 App 生命周期驱动而不是弹窗驱动MenuStatsModel 每 3 秒轮询一轮每个采集器系统统计、网速、连接设备、建议提示都被一个超时预算包围单个系统调用卡死 → 该指标保留上次值面板不白屏超 500ms 的步骤会打 OSLog 警告方便用户从 Console 定位到具体采集器轮询在applicationDidFinishLaunching启动不依赖 popover 的 onAppear后者在 Intel macOS 14.x 上不可靠是面板卡在加载转圈的旧 bug。跨进程共享状态一个 plist 就够了主应用和菜单栏 Helper 通过命名 UserDefaults suite交换状态见 SharedAppState.swift最近一次恶意软件扫描结果、被用户关闭的提示、通知节流日志。共享数据小、可 JSON 序列化、不涉密所以没上 App Group——注释里明确记录了为什么不用标准方案的取舍理由。保活策略纯函数决定要不要重启Helper 意外退出后主应用监听NSWorkspace.didTerminateApplicationNotification决定是否拉起。决策逻辑同样是纯函数 MenuBarKeepAlivePolicy.action关闭开关 → terminate用户主动退出监视器写入menuBarWidgetUserQuit标记→ 不再拉起register()之后先等 500ms 让 SMAppService 有机会自行拉起避免第二条启动路径竞态。Swift 6 严格并发从注释能读出的实战经验swift-tools-version: 6.0意味着默认开启严格并发检查以下模式在代码中反复出现actor 隔离可变状态MaintenanceExecutor 用 actor 串行化维护任务MainActor 标注 UI 状态MenuBarLauncher、MenuStatsModel全部MainActor Observable跨线程回调统一用Task { MainActor in }跳回主 actor注释标注了不要用会触碰 MainActor 状态的 completion handlerissue #58Sendable 协议贯穿数据模型ScanModule、MenuBarInstance、MaintenanceShell结果类型均为Sendable可在Task间自由传递桥接非线程安全 APINSAppleScript不是线程安全的且可能阻塞数分钟因此放到专用 DispatchQueue用withCheckedContinuation包进 async 世界AppleScriptPrivilegedRunner后台工作不让窗口卡AppState初始化时用Task.detached(priority: .background)做日志清理与语言发现AppState.swift慢文件系统不延迟窗口出现preconcurrency 兼容旧 SDKMenuAppDelegate 对NSApplicationDelegate使用preconcurrency标注在 CI 旧 SDK 上保持可编译。模块体系同样受益于并发安全14 个扫描模块在 AppState.registerModules 统一注册到 ScanCoordinatoridle / scanning / completed / failed状态机驱动 Smart Scan 的一键清理流程。本地构建与测试git clone https://gitcode.com/gh_mirrors/mac/MacSai cd MacSai swift build swift test测试覆盖策略类纯函数如MenuBarHelperPolicy到端到端场景EndToEndScenarioTests完整说明见 docs/TESTING.md发布流程见 docs/RELEASING.md。小结Mac Sai 的架构可以浓缩为三句话4 目标分工——MacCleanKit承载全部可测的纯逻辑两个可执行目标只做薄 I/O无特权 Helper 的权限方案——进程内 AppleScript 换一次密码框Login Item 换常驻监视器能不提权就不提权Swift 6 严格并发不是负担而是护栏——actor、Sendable、MainActor 让多进程 3 秒轮询 异步扫描这类场景在编译期就排除了数据竞争。对一个追求安全设计的清理工具来说这些取舍比功能清单更能解释它为什么敢开源。赞分享【免费下载链接】MacSaiMac Sai: the open-source Mac cleaner, optimizer, and malware scanner. A free, Apple-notarized alternative to CleanMyMac, built with Swift 6 and SwiftUI.项目地址https://gitcode.com/gh_mirrors/mac/MacSai点击查看免费下载相关推荐ECC 规则体系中的 Swift 编码风格格式、不可变性、Swift 6 类型化错误与严格并发的完整实践ECC 规则体系中的 Swift 编码风格格式、不可变性、Swift 6 类型化错误与严格并发的完整实践 在 ECCagent harness 性能优化系统人工智能AI 技能AI 插件AI 评测Agent 评测MCP Clients开发工具Tinycast 架构深度解析四层分层、单所有者核心与 Swift 6 并发模型Tinycast 架构深度解析四层分层、单所有者核心与 Swift 6 并发模型 Tinycast 是一个完全原生的 macOS 启动器、热键与剪贴板历史工具桌面应用Sparkle 2 框架架构设计实践XPC 服务、非单例化与 Objective-C 代码瘦身指南Sparkle 2 框架架构设计实践XPC 服务、非单例化与 Objective C 代码瘦身指南 导读 本文以 Sparkle 2 的官方架构设计文档 De桌面应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Windows终端AI编程:OpenCode+GLM+oh-my-opencode配置实战

Windows终端AI编程:OpenCode+GLM+oh-my-opencode配置实战

Windows 上玩转终端 AI 编程,其实没有想象中那么折腾。OpenCode 这款终端 AI 编程助手,加上 oh-my-opencode 这个配置增强层,再接入 GLM 系列模型,三样东西拼在一起,就能在本地跑出一套完整可控、中文友好、token 成本…

2026/10/11 13:20:55 阅读更多 →
多端电商系统源码深度解析:架构设计与实践指南

多端电商系统源码深度解析:架构设计与实践指南

1. 为什么我建议你重新思考“多端电商系统”这件事这些年后台私信里被问到最多的问题之一,就是“我想做个商城,小程序、App、H5都要有,有没有现成的源码能直接拿来用?”说实话,多端电商系统源码这个概念,市…

2026/10/11 13:20:55 阅读更多 →
如何用ruyiPage获取closed shadow root:iframe与shadow DOM深层元素完整指南

如何用ruyiPage获取closed shadow root:iframe与shadow DOM深层元素完整指南

【免费下载链接】ruyipage 下一代Python的web自动化过检测框架,AI自我调试运行,trace日志可分析一切网页链路,通过一切网站检测的Firefox指纹浏览器。RuyiPage is a Python-based Firefox automation framework built on the next-generation…

2026/10/11 13:20:55 阅读更多 →

最新新闻

近封装光互连(NPO):破解AI芯片带宽墙的系统级解法

近封装光互连(NPO):破解AI芯片带宽墙的系统级解法

1. 项目概述:当芯片封装不再只是“包饺子”,光互连开始在硅片边缘下棋近封装光互连(NPO)这五个字,过去十年里在高端芯片设计圈里,从一个实验室术语,慢慢变成了流片前必须拉齐的跨部门议题。它不…

2026/10/11 14:11:21 阅读更多 →
Spring Boot+微信小程序音乐播放器毕设项目全解析:从架构到部署

Spring Boot+微信小程序音乐播放器毕设项目全解析:从架构到部署

每年到了毕业设计赶工季,总有一批同学会栽在“基于Spring Boot的音乐播放器小程序”这类题目上。标题看起来很唬人,其实骨架非常清晰:前端一个小程序壳子,后端一个Spring Boot工程,中间串上MySQL数据库,能完…

2026/10/11 14:11:21 阅读更多 →
PyTorch实现MNIST手写数字识别:CNN模型搭建与训练避坑指南

PyTorch实现MNIST手写数字识别:CNN模型搭建与训练避坑指南

简介:这是一套基于Python与MNIST数据集实现的CNN手写数字识别项目,面向高校毕业设计、课程设计与开发者项目实践。项目基于TensorFlow搭建卷积神经网络模型,通过优化器训练并保存模型变量,识别阶段复用已保存权重;同时…

2026/10/11 14:11:21 阅读更多 →
免费C++小游戏集合:源码解析、环境配置与调试实战

免费C++小游戏集合:源码解析、环境配置与调试实战

简介:一份收录了多种经典小游戏的C代码合集,面向初学编程的读者和游戏开发爱好者。通过阅读、运行和修改这些源码,可以系统巩固变量、循环、条件判断、函数、数组以及类与对象等C核心概念。压缩包内共117个文件,以115个cpp源文件为…

2026/10/11 14:11:21 阅读更多 →
Django+Python影城售票系统:从数据建模到并发锁座的完整实战

Django+Python影城售票系统:从数据建模到并发锁座的完整实战

做这个项目的人我见过不少,各种课设、毕设、还有想转行拿来做作品集的,但说实话,十个里有八个做的只是“换皮图书管理系统”——能增删改查电影和场次,再让用户注册登录,然后就没然后了。前阵子我帮人改造一个类似的模…

2026/10/11 14:11:21 阅读更多 →
@reach/router 程序化导航完全指南:navigate() API 用法与源码原理剖析

@reach/router 程序化导航完全指南:navigate() API 用法与源码原理剖析

前端 【免费下载链接】router 项目地址&#xff1a; https://gitcode.com/gh_mirrors/rou/router 点击查看 免费下载 本文以 reach/router 的 navigate 函数为核心&#xff0c;系统讲解在 React 应用中如何通过代码触发路由跳转&#xff08;而非依赖用户点击 <Link>&…

2026/10/11 14:10:20 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →