name: ios-dev-guidelines description: 上下文感知路由到Swift/iOS开发模式、架构和最佳实践。当处理.swift文件、ViewModels、Coordinators、重构或讨论Swift/SwiftUI模式时使用。
iOS开发指南(智能路由)
目的
上下文感知路由到iOS开发模式、代码风格和架构指南。这个技能提供关键规则并指向全面文档。
自动激活时
- 处理
.swift文件时 - 讨论ViewModels、Coordinators、架构时
- 重构或格式化代码时
- 关键词:swift、swiftui、mvvm、async、await、refactor
🚨 关键规则(绝不违反)
- 绝不修剪仅含空白字符的行 - 保留空白行及其中的空格/制表符,保持原样
- 绝不编辑生成的文件 - 标记为
// Generated using Sourcery/SwiftGen的文件 - 绝不在UI中使用硬编码字符串 - 始终使用本地化常量(
Loc.*) - 绝不添加注释,除非明确请求
- 重构时始终更新测试和模拟对象 - 搜索所有引用并更新
- 新功能使用功能标志 - 包裹实验性代码以确保安全推出
📋 快速检查清单
完成任务前:
- [ ] 仅含空白字符的行已保留(未修剪)
- [ ] 无硬编码字符串(使用
Loc常量) - [ ] 如果依赖项更改,测试和模拟对象已更新
- [ ] 生成的文件未编辑
- [ ] 新功能已应用功能标志
- [ ] 未添加注释(除非请求)
🎯 SwiftUI视图基础(WWDC24)
SwiftUI视图有三个关键特性:
- 声明式 - 描述你想要的,而不是如何构建它
- 组合式 - 从简单构建块构建复杂UI
- 状态驱动 - UI在状态更改时自动更新
关键见解:视图是值类型(结构体),而非长寿命对象。它们是当前UI状态的描述。将视图拆分为子视图不会损害性能——SwiftUI在幕后维护高效的数据结构。
// 声明式:描述结果,而非步骤
List(pets) { pet in
HStack {
Text(pet.name)
Spacer()
Text(pet.species)
}
}
// 无需手动添加/删除行——SwiftUI处理
有关详细SwiftUI模式,请参见swiftui-patterns-developer技能。
🎯 常见模式
MVVM ViewModel
@MainActor
final class ChatViewModel: ObservableObject {
@Published var messages: [Message] = []
@Injected(\.chatService) private var chatService
func sendMessage(_ text: String) async {
// 业务逻辑在此
}
}
Coordinator
@MainActor
final class ChatCoordinator: ObservableObject {
@Published var route: Route?
enum Route {
case settings
case memberList
}
}
依赖注入
extension Container {
var chatService: Factory<ChatServiceProtocol> {
Factory(self) { ChatService() }
}
}
// 在ViewModel中使用
@Injected(\.chatService) private var chatService
ViewModel初始化
保持ViewModelinit()轻量——将繁重工作延迟到.task:
// 初始化仅分配参数
init(id: String) {
_model = State(wrappedValue: ViewModel(id: id))
}
// 繁重工作在.task中
.task { await model.startSubscriptions() }
对于昂贵的初始化,完全延迟创建:
@State private var model: ViewModel?
.task(id: id) { model = ViewModel(id: id) }
异步按钮操作
首选AsyncStandardButton而非手动加载状态管理,以获得更简洁代码:
// ❌ 避免:手动加载状态
struct MyView: View {
@State private var isLoading = false
var body: some View {
StandardButton(.text("连接"), inProgress: isLoading, style: .secondaryLarge) {
isLoading = true
Task {
await viewModel.connect()
isLoading = false
}
}
}
}
// ✅ 首选:AsyncStandardButton自动处理加载状态
struct MyView: View {
var body: some View {
AsyncStandardButton(Loc.sendMessage, style: .primaryLarge) {
try await viewModel.onConnect()
}
}
}
// ViewModel可抛出错误——错误自动处理
func onConnect() async throws {
guard let identity = details?.identity, identity.isNotEmpty else { return }
if let existingSpace = spaceViewsStorage.oneToOneSpaceView(identity: identity) {
pageNavigation?.open(.spaceChat(SpaceChatCoordinatorData(spaceId: existingSpace.targetSpaceId)))
return
}
let newSpaceId = try await workspaceService.createOneToOneSpace(oneToOneIdentity: identity)
pageNavigation?.open(.spaceChat(SpaceChatCoordinatorData(spaceId: newSpaceId)))
}
AsyncStandardButton的好处:
- 内部管理
inProgress状态 - 失败时自动显示错误提示
- 提供触觉反馈(点击时选择,失败时错误)
- 更简洁的ViewModel(无需
@Published var isLoading) - 操作是
async throws——使用try await并让错误自然传播
🗂️ 项目结构
Anytype/Sources/
├── ApplicationLayer/ # 应用生命周期、Coordinators
├── PresentationLayer/ # UI组件、ViewModels
├── ServiceLayer/ # 业务逻辑、数据服务
├── Models/ # 数据模型、实体
└── CoreLayer/ # 核心实用工具、网络
🔧 代码风格快速参考
- 缩进:4个空格(无制表符)
- 命名:PascalCase(类型)、camelCase(变量/函数)
- 扩展:
TypeName+Feature.swift - 属性顺序:@Published/@Injected → 公共 → 私有 → 计算 → init → 方法
- 避免嵌套类型——提取到顶层并赋予描述性名称
- 枚举穷举性——使用显式switch语句(启用编译器警告)
📚 完整文档
完整指南:Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md
涵盖以下内容:
- 详细格式化规则
- Swift最佳实践(guard、@MainActor、async/await)
- 架构模式(MVVM、Coordinator、Repository)
- 属性组织
- 历史常见错误
- 测试和模拟对象管理
- 完整代码示例
🚨 常见错误(历史)
自主提交(2025-01-28)
绝不无明确用户请求提交——提交具有破坏性
通配符文件删除(2025-01-24)
使用rm -f .../PublishingPreview*.swift——删除了主要UI组件
- 始终先用
ls检查 - 逐个删除文件
不完整模拟更新(2025-01-16)
重构了依赖项但忘记MockView.swift
- 搜索:
rg "oldName" --type swift - 更新:测试、模拟对象、DI注册
🔗 相关技能和文档
- swiftui-patterns-developer → 视图结构、组合、@Observable模式
- swiftui-performance-developer → 性能审计、视图无效化
- localization-developer →
LOCALIZATION_GUIDE.md- 本地化系统 - code-generation-developer →
CODE_GENERATION_GUIDE.md- 功能标志、make generate - design-system-developer →
DESIGN_SYSTEM_MAPPING.md- 图标、排版
导航:这是一个智能路由。如需深入技术细节,请始终参考IOS_DEVELOPMENT_GUIDE.md。