名称: Swift/SwiftUI 开发 描述: 使用 Swift 和 SwiftUI 进行原生 iOS 开发的专家技能 版本: 1.0.0 类别: 原生 iOS 开发 标识符: swift-swiftui 状态: 活跃
Swift/SwiftUI 开发技能
概述
此技能提供使用 Swift 和 SwiftUI 进行原生 iOS 开发的专家级能力。它能够生成 SwiftUI 视图、实现状态管理模式、进行 Combine 响应式编程以及执行全面的 Xcode 构建操作。
允许使用的工具
bash- 执行 xcodebuild、swift 和 xcrun 命令read- 分析 Swift 源文件和 Xcode 项目配置write- 生成和修改 Swift 代码及 SwiftUI 视图edit- 更新现有的 Swift 代码和配置glob- 搜索 Swift 文件和 Xcode 项目文件grep- 在 Swift 代码库中搜索模式
能力
SwiftUI 开发
-
视图生成
- 创建结构正确的 SwiftUI 视图
- 为自定义容器实现 ViewBuilder
- 构建可重用的视图修饰符
- 生成预览提供器
- 创建环境感知视图
-
状态管理
- 使用 @State 实现本地视图状态
- 使用 @Binding 实现双向绑定
- 配置 @ObservedObject 和 @StateObject
- 使用 @EnvironmentObject 实现依赖注入
- 使用 @AppStorage 集成 UserDefaults
-
导航
- 配置基于路径路由的 NavigationStack
- 实现 NavigationLink 和 NavigationDestination
- 设置带有程序化选择的 TabView
- 处理 sheet 和 fullScreenCover 展示
- 通过 URL 处理实现深度链接
Combine 框架
-
响应式模式
- 创建发布者和订阅者
- 实现自定义 Combine 操作符
- 处理错误传播和恢复
- 使用 @Published 实现可观察属性
- 使用 AnyCancellable 配置取消
-
数据流
- 实现 PassthroughSubject 和 CurrentValueSubject
- 为用户输入配置防抖和节流
- 链接操作符进行数据转换
- 使用 Future 处理异步操作
Swift 包管理器
- 包管理
- 为依赖项配置 Package.swift
- 创建本地 Swift 包
- 实现包产品和目标
- 配置二进制依赖项
- 设置包插件
Xcode 构建系统
-
构建操作
- 执行 xcodebuild 进行编译
- 配置构建方案和配置
- 实现归档和导出工作流
- 使用配置文件设置代码签名
- 为崩溃报告生成 dSYM 文件
-
代码签名
- 配置自动代码签名
- 设置手动预配配置文件
- 实现证书管理
- 配置权利文件
- 处理 App Groups 和功能
测试
-
XCTest 框架
- 使用 XCTestCase 编写单元测试
- 使用 XCUITest 实现 UI 测试
- 配置测试计划和方案
- 设置代码覆盖率收集
- 为测试创建模拟对象
-
性能测试
- 使用 XCTMetric 进行性能测量
- 配置 Instruments 配置文件
- 实现内存测试
- 分析能耗影响
- 分析启动时间
目标流程
此技能与以下流程集成:
swiftui-app-development.js- SwiftUI 应用架构ios-core-data-implementation.js- Core Data 集成ios-push-notifications.js- APNs 配置ios-appstore-submission.js- App Store 提交mobile-accessibility-implementation.js- 无障碍功能
依赖项
必需项
- Xcode 15+
- Swift 5.9+
- macOS 14+ (Sonoma)
可选项
- Instruments
- SF Symbols 应用
- Swift Playgrounds
- TestFlight
配置
项目结构
MyApp/
├── MyApp/
│ ├── App/
│ │ ├── MyAppApp.swift
│ │ └── ContentView.swift
│ ├── Features/
│ │ └── FeatureName/
│ │ ├── Views/
│ │ ├── ViewModels/
│ │ └── Models/
│ ├── Core/
│ │ ├── Extensions/
│ │ ├── Utilities/
│ │ └── Services/
│ ├── Resources/
│ │ └── Assets.xcassets
│ └── Info.plist
├── MyAppTests/
├── MyAppUITests/
└── MyApp.xcodeproj
SwiftUI 应用入口点
// MyAppApp.swift
import SwiftUI
@main
struct MyAppApp: App {
@StateObject private var appState = AppState()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(appState)
}
}
}
使用示例
创建 SwiftUI 视图
// Features/Home/Views/HomeView.swift
import SwiftUI
struct HomeView: View {
@StateObject private var viewModel = HomeViewModel()
@State private var searchText = ""
var body: some View {
NavigationStack {
List {
ForEach(viewModel.filteredItems) { item in
NavigationLink(value: item) {
ItemRowView(item: item)
}
}
}
.navigationTitle("首页")
.searchable(text: $searchText)
.onChange(of: searchText) { _, newValue in
viewModel.search(query: newValue)
}
.navigationDestination(for: Item.self) { item in
ItemDetailView(item: item)
}
.refreshable {
await viewModel.refresh()
}
}
}
}
#Preview {
HomeView()
}
使用 Combine 实现 ViewModel
// Features/Home/ViewModels/HomeViewModel.swift
import Foundation
import Combine
@MainActor
final class HomeViewModel: ObservableObject {
@Published private(set) var items: [Item] = []
@Published private(set) var filteredItems: [Item] = []
@Published private(set) var isLoading = false
@Published private(set) var error: Error?
private let itemService: ItemServiceProtocol
private var cancellables = Set<AnyCancellable>()
init(itemService: ItemServiceProtocol = ItemService()) {
self.itemService = itemService
setupBindings()
Task { await loadItems() }
}
private func setupBindings() {
$items
.assign(to: &$filteredItems)
}
func loadItems() async {
isLoading = true
error = nil
do {
items = try await itemService.fetchItems()
} catch {
self.error = error
}
isLoading = false
}
func search(query: String) {
if query.isEmpty {
filteredItems = items
} else {
filteredItems = items.filter { $0.title.localizedCaseInsensitiveContains(query) }
}
}
func refresh() async {
await loadItems()
}
}
创建自定义视图修饰符
// Core/ViewModifiers/CardStyle.swift
import SwiftUI
struct CardStyle: ViewModifier {
var cornerRadius: CGFloat = 12
var shadowRadius: CGFloat = 4
func body(content: Content) -> some View {
content
.background(Color(.systemBackground))
.cornerRadius(cornerRadius)
.shadow(color: .black.opacity(0.1), radius: shadowRadius, x: 0, y: 2)
}
}
extension View {
func cardStyle(cornerRadius: CGFloat = 12, shadowRadius: CGFloat = 4) -> some View {
modifier(CardStyle(cornerRadius: cornerRadius, shadowRadius: shadowRadius))
}
}
配置带深度链接的导航
// App/Router.swift
import SwiftUI
enum Route: Hashable {
case home
case detail(id: String)
case settings
case profile(userId: String)
}
final class Router: ObservableObject {
@Published var path = NavigationPath()
func navigate(to route: Route) {
path.append(route)
}
func navigateBack() {
path.removeLast()
}
func navigateToRoot() {
path.removeLast(path.count)
}
func handle(url: URL) -> Bool {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
let host = components.host else {
return false
}
switch host {
case "detail":
if let id = components.queryItems?.first(where: { $0.name == "id" })?.value {
navigate(to: .detail(id: id))
return true
}
case "profile":
if let userId = components.queryItems?.first(where: { $0.name == "userId" })?.value {
navigate(to: .profile(userId: userId))
return true
}
default:
break
}
return false
}
}
构建命令
# 为模拟器构建
xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15 Pro' build
# 为设备构建
xcodebuild -scheme MyApp -destination 'generic/platform=iOS' build
# 为分发归档
xcodebuild -scheme MyApp -archivePath ./build/MyApp.xcarchive archive
# 导出 IPA
xcodebuild -exportArchive -archivePath ./build/MyApp.xcarchive -exportPath ./build -exportOptionsPlist ExportOptions.plist
# 运行测试
xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15 Pro'
质量门限
代码质量
- Swift 编译器警告视为错误
- 符合 SwiftLint 严格规则
- 生产代码中无强制解包
- 正确的访问控制修饰符
性能基准
- 应用启动时间 < 1 秒 (冷启动)
- 流畅的 120fps 动画 (ProMotion 设备)
- 内存使用符合 App Store 指南
- 无主线程检查器警告
测试覆盖率
- 单元测试覆盖率 > 80%
- 关键流程的 UI 测试覆盖率
- 关键操作的性能测试
错误处理
常见问题
-
Xcode 构建缓存问题
rm -rf ~/Library/Developer/Xcode/DerivedData -
代码签名问题
security find-identity -v -p codesigning -
Swift 包解析问题
swift package resolve # 或在 Xcode 中: 文件 > 包 > 重置包缓存 -
模拟器问题
xcrun simctl erase all
相关技能
ios-persistence- Core Data 和 Realm 集成push-notifications- APNs 配置mobile-security- iOS 安全实现app-store-connect- App Store 提交
版本历史
- 1.0.0 - 初始版本,包含核心 Swift/SwiftUI 能力