news 2026/5/2 0:31:28

独立开发订阅管理App技术复盘:SwiftData踩坑、周期换算与风险检测

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
独立开发订阅管理App技术复盘:SwiftData踩坑、周期换算与风险检测

起因:信用卡账单上那笔想不起来的扣费

去年年底,我翻信用卡账单的时候发现一笔 15 块的扣费,死活想不起来是什么。查了半天才发现是某个 App 的试用期过了自动续费了——我甚至都没打开过第二次。

这事儿让我挺不爽的。我就想,能不能做一个工具把自己所有的订阅服务都记下来,哪些该续、哪些该砍,一眼就能看清楚。

于是「订阅斩」就这么开始做了。

产品定位:不只是记账,要有「斩掉」的仪式感

市面上有不少订阅管理工具,但大多数做法就是一个列表加一个总价。我觉得这不够——问题不在于「看见」,在于「行动」。

所以我给 App 设计了一个核心交互隐喻:。你不是在删除一条记录,你是在斩断一笔持续失血的开支。停用之后它会进入「已斩」Tab,带有一种完成任务的成就感。

说白了就是把无聊的记账操作包装成带点游戏感的动作。

技术选型:SwiftData + Swift 6

项目从一开始就用了 SwiftData 做持久化。说实话当时 SwiftData 刚出来不久,踩了不少坑,但好处是跟 SwiftUI 的数据流配合很顺畅,不用写一堆 NSFetchedResultsController 的样板代码。

核心的数据模型是Subscription,长这样:

@ModelfinalclassSubscription{varid:UUIDvarname:Stringvarprice:Doublevarcycle:Int// 0=月付, 1=季付, 2=年付varisTrial:BoolvarnextBillingDate:Datevarstatus:Int// 活跃 / 已斩varkilledDate:Date?varisShared:BoolvarmembersCount:Intvaricon:StringvarunsubscribeURL:Stringvarsource:IntvarcategoryStorage:String?}``` 这里有个设计取舍:`cycle` 和 `status` 我存的是IntrawValue 而不是直接存枚举。原因是SwiftData对枚举的迁移支持当时还不太稳定,用Int更保险,上层再包一个计算属性转回枚举就行。 ## 账单周期统一换算 用户录入订阅时可以选月付、季付、年付,但仪表盘要展示的是「每月总支出」,所以需要把所有订阅统一折算成月度金额: ```swiftenumBillingCycle:Int,CaseIterable{casemonthly=0casequarterly=1caseyearly=2varmultiplierToMonthly:Double{switchself{case.monthly:1case.quarterly:1.0/3.0case.yearly:1.0/12.0}}}``` 计算月度开销的时候,每条订阅的 `price*billingCycle.multiplierToMonthly` 再求和就行。看着简单,但我一开始犯了个低级错误——季付写成了 `3.0/1.0`,导致仪表盘显示的金额离谱地高,自己测试的时候还以为是UI刷新问题,排查了好一阵。 ## 风险检测:哪些订阅该「斩」 这是我比较满意的一个功能。App会根据几个维度给每条订阅打风险标签:-**高危**:试用期订阅且距离下次扣费不到3天(很多人就是在这个窗口期忘了取消)--**中危**:超过60天没有手动确认仍需要的订阅 中危这个怎么判定呢?实现上很简单——每条订阅详情页有个「我仍需要」的按钮,用户点击后会重置一个 `lastConfirmedDate` 时间戳。App拿当前日期跟这个时间戳做 diff,超过60天就标中危。如果你从来没点过这个按钮,那从创建日期开始算。 另外共享订阅会降低风险权重(毕竟分摊了成本,单人月均花费低)。 逻辑不复杂,但实测下来确实能帮自己抓出不少「订阅刺客」。我自己用了两个月,砍掉了4个订阅,每月省了大概80块。 ## 内置订阅预设库 为了降低用户录入成本,我在代码里维护了一个 `SubscriptionCatalog`,内置了常见订阅服务的预设信息——名称、图标、默认周期、参考价格、是否适合共享等。用户输入名称的时候会做模糊匹配,命中预设就自动填充其他字段。 目前收录了NetflixYouTubePremiumDisney+Spotify、iCloud+这些主流服务,还有国内的爱奇艺、B站大会员、QQ音乐等。这个库还在慢慢补充。 ## 提醒系统 `AppSettings` 里有三档提醒配置:提前7天、3天、1天。我用UserNotifications在每次订阅数据变更时重新计算并注册本地通知。 这里有个细节:iOS 对本地通知的 pending 数量有64条的限制。如果用户录了很多订阅且三档全开,很容易超限。我的做法是按紧急程度排序,优先注册距离最近的扣费提醒,超出的部分下次打开App时再补。 ## 多币种支持 因为我自己有美元订阅也有人民币订阅(对,就是那些海外SaaS工具),所以App支持多币种显示。默认币种根据设备Locale自动推断:-`CNY` → ¥--`USD` → $--`JPY` →JP¥--`TWD` →NT$--其他一律 fallback 到 ¥ 为什么 fallback 选 ¥ 而不是 $ 或者直接显示货币代码?原因很实际——我的目标用户绝大多数是中文用户,设备Locale拿不到货币信息的情况基本只发生在一些小众地区设置上,这种边缘case显示 ¥ 比显示一个用户可能不认识的三字母代码(比如MYRTHB)体验更好。以后如果海外用户多了再改成显示货币代码也来得及。 ## 上架情况App2024年底上架AppStore,当前版本1.2。感兴趣的可以在AppStore搜「订阅斩」。 说实话下载量还很少,独立开发最难的不是写代码,是让别人知道你做了这东西。没有投过广告,也没找人推过,就靠自然搜索慢慢来。 ## 几个踩坑点总结1.**SwiftData的 `@Attribute(originalName:)` 是救命的**。我中途改过好几次字段名,有这个注解才不至于丢用户数据。2.**枚举存 rawValue 虽然丑但稳**Swift的类型安全是好事,但持久化层还是得对迁移友好一点。3.**游戏化设计比我预想的有效**。加了「已斩」计数器之后,我自己都会有冲动去多砍几个订阅。这算是产品设计中一个小验证。4.**预设库的模糊匹配最初用的是 `contains`,后来改成了加权评分**。因为 `contains` 会把"Apple TV+"匹配到所有带"apple"的预设上,误报太多。 ## 下一步计划-支持OCR识别截图中的订阅信息(已经做了基础版本,每日有免费额度限制)--iCloud 同步(模型层已经预留了 `iCloudSyncEnabled` 字段)--考虑做一个HarmonyOSNEXT版本,ArkTS+ArkUI那套我还在学,等 iOS 版稳定了再说---对了,想问问同样在做 iOS 独立开发的朋友:你们现在持久化选SwiftData还是CoreDataSwiftData的 lightweight migration 你们踩过坑吗?我遇到过改字段类型之后 migration 静默失败的情况,最后是靠 `@Attribute(originalName:)` 绕过去的,不知道有没有更好的解法。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/2 0:30:32

在 Node.js 后端服务中集成 Taotoken 实现多模型对话功能

在 Node.js 后端服务中集成 Taotoken 实现多模型对话功能 1. 准备工作与环境配置 在开始集成 Taotoken 之前,需要确保 Node.js 环境已就绪。推荐使用 Node.js 18 或更高版本以获得稳定的异步操作支持。通过以下命令检查当前环境: node -v npm -v安装必…

作者头像 李华
网站建设 2026/5/2 0:26:26

软件工程师在TVA产业化浪潮中的角色定位与机遇(9)

重磅预告:本专栏将独家连载新书《AI视觉技术:从入门到进阶》精华内容。本书是《AI视觉技术:从进阶到专家》的权威前导篇,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan师从美国三院院士、“AI教母”…

作者头像 李华
网站建设 2026/5/2 0:16:42

像素觉醒・坐标落地:2026 室外无感定位,重构数字孪生空间基准

像素觉醒・坐标落地:2026 室外无感定位,重构数字孪生空间基准本报讯(记者 XXX)2026年,室外数字孪生感知技术迎来革命性突破,镜像视界凭借技术自研实力,以“像素觉醒・坐标落地”为核心导向&…

作者头像 李华
网站建设 2026/5/2 0:11:11

SpaceTools:基于工具增强与强化学习的空间推理模型

1. SpaceTools项目概述SpaceTools是一个基于工具增强与交互式强化学习的空间推理模型,旨在提升视觉语言模型(VLMs)在复杂空间任务中的表现。这个项目由Toolshed系统提供支持,能够大规模部署多样化工具进行在线交互训练。实验结果表明,SpaceTo…

作者头像 李华