第 19 课:移动端开发 — Swift / SwiftUI / Dart / Flutter

所属阶段:第四阶段「语言与框架」(第 17-22 课) 前置条件:第 17 课(后端语言) 本课收获:了解移动端 Skill 体系,能分析 Anti-Patterns


一、本课概述

移动端开发有自己独特的世界 --- UI 线程安全、设备资源限制、平台审核规范、离线支持。ECC 为 Swift/SwiftUI 和 Dart/Flutter 两大生态提供了深度 Skill 支持,甚至覆盖了最前沿的设备端 LLM 集成。

本课回答三个问题:

  1. Swift 生态有哪些 Skill? --- 从 SwiftUI 到 Swift 6.2 并发模型
  2. Flutter/Dart 生态有哪些 Skill? --- 跨平台架构与代码审查
  3. 移动端 Skill 的 Anti-Patterns 是什么? --- 从反面学习最佳实践

二、Swift 生态 Skill 全景

2.1 Skill 清单

Swift 是 ECC 中移动端 Skill 最丰富的语言,共 5 个专用 Skill:

Skill 定位 核心主题
swiftui-patterns SwiftUI 架构 @Observable 状态管理、视图组合、导航
swift-concurrency-6-2 Swift 6.2 并发 单线程默认、@concurrent、actor 隔离
swift-actor-persistence Actor 持久化 Actor 线程安全持久化、CoreData/SwiftData
swift-protocol-di-testing 协议与测试 协议 DI、可测试性设计、Mock 策略
foundation-models-on-device 设备端 AI 设备端 LLM、@Generable 宏

2.2 Skill 关系图

csharp 复制代码
                 swiftui-patterns
              (UI 层:视图 + 状态 + 导航)
                    │
         ┌──────────┼──────────┐
         │          │          │
         ▼          ▼          ▼
  swift-concurrency  swift-actor   swift-protocol
      -6-2          -persistence    -di-testing
   (并发模型)     (持久化层)    (可测试性)
                    │
                    ▼
         foundation-models
            -on-device
          (设备端 AI)

这些 Skill 形成了一条从 UI 到底层的完整链:SwiftUI 视图 → 并发安全 → 数据持久化 → 协议抽象 → 设备端 AI。


三、swiftui-patterns 深入

3.1 @Observable 状态管理

Swift 5.9 引入了 @Observable 宏,取代了 ObservableObject 协议。swiftui-patterns Skill 强调新模式:

swift 复制代码
// 旧模式(Swift 5.8 及之前)--- 不再推荐
class UserViewModel: ObservableObject {
    @Published var name: String = ""
    @Published var email: String = ""
}

// 新模式(Swift 5.9+)--- 推荐
@Observable
class UserViewModel {
    var name: String = ""
    var email: String = ""
}

关键区别@Observable 实现了属性级别 的变更追踪,而不是整个对象级别。这意味着当 name 变化时,只有用到 name 的视图会重新渲染,用到 email 的视图不受影响。

3.2 视图组合原则

swiftui-patterns 推荐的视图组织方式:

css 复制代码
视图层级:
  Screen(屏幕)     → 顶层容器,处理导航和数据获取
    Section(区块)   → 逻辑分组
      Component(组件)→ 可复用的 UI 单元
        Element(元素)→ 最小 UI 原语

Anti-Pattern:巨型视图

swift 复制代码
// WRONG --- 一个视图做了太多事情(God View)
struct UserProfileScreen: View {
    var body: some View {
        ScrollView {
            // 头像区域 ... 50 行
            // 个人信息 ... 80 行
            // 设置列表 ... 100 行
            // 底部操作 ... 30 行
        }
    }
}

// CORRECT --- 拆分为子组件
struct UserProfileScreen: View {
    var body: some View {
        ScrollView {
            AvatarSection(user: user)
            InfoSection(user: user)
            SettingsSection(settings: settings)
            ActionBar(onLogout: handleLogout)
        }
    }
}

3.3 导航模式

SwiftUI 的导航经历了多次演进。swiftui-patterns 推荐 NavigationStack 模式:

swift 复制代码
// 推荐:NavigationStack + NavigationPath
@Observable
class Router {
    var path = NavigationPath()

    func push(_ destination: Destination) {
        path.append(destination)
    }

    func pop() {
        path.removeLast()
    }

    func popToRoot() {
        path.removeLast(path.count)
    }
}

四、Swift 6.2 并发模型

4.1 swift-concurrency-6-2 核心变化

Swift 6.2 带来了并发模型的重大变化。swift-concurrency-6-2 Skill 是理解这些变化的关键:

核心变化:默认单线程

perl 复制代码
Swift 6.1 及之前:
  nonisolated 函数 → 可能在任意线程执行

Swift 6.2:
  nonisolated 函数 → 默认在 caller 的 actor 上执行
  @concurrent 标注  → 显式声明"可以在其他线程执行"

为什么这样设计?

大多数代码不需要并发执行。默认单线程减少了数据竞争的风险,需要并发时显式标注 @concurrent

4.2 Actor 隔离

swift 复制代码
actor DatabaseManager {
    private var cache: [String: Data] = [:]

    func fetch(key: String) -> Data? {
        // 这里是 actor 隔离的 --- 线程安全
        return cache[key]
    }

    func store(key: String, value: Data) {
        // 同一时刻只有一个任务能执行
        cache[key] = value
    }
}

4.3 swift-actor-persistence

swift-actor-persistence Skill 处理一个棘手问题:如何在 Actor 隔离的约束下进行数据持久化。

复制代码
问题:
  CoreData/SwiftData 的 context 不是线程安全的
  Actor 保证了内部状态的线程安全
  如何让两者协作?

解决方案:
  ModelActor 宏 --- 创建一个绑定到特定 context 的 Actor
swift 复制代码
@ModelActor
actor PersistenceActor {
    func createUser(name: String) throws -> User {
        let user = User(name: name)
        modelContext.insert(user)
        try modelContext.save()
        return user
    }
}

五、设备端 LLM 集成

5.1 foundation-models-on-device

这是 ECC 中最前沿的 Skill 之一。Apple 在 iOS 26 / macOS 26 中引入了 Foundation Models 框架,允许在设备上运行 LLM。

@Generable 宏

swift 复制代码
@Generable
struct RecipeSuggestion {
    var title: String
    var ingredients: [String]
    var steps: [String]
    var estimatedTime: Int
}

// 使用
let session = LanguageModelSession()
let suggestion: RecipeSuggestion = try await session.respond(
    to: "Suggest a quick pasta recipe",
    generating: RecipeSuggestion.self
)

设备端 vs 云端 LLM

维度 设备端 云端
隐私 数据不离开设备 数据上传到服务器
延迟 无网络延迟 受网络影响
能力 受限于设备算力 几乎无限
离线 可用 不可用
成本 免费 按 token 计费

六、Flutter / Dart 生态

6.1 Skill 清单

Skill 定位 核心主题
dart-flutter-patterns Dart + Flutter 架构 空安全、状态管理、Widget 架构、GoRouter
flutter-dart-code-review 代码审查 Widget 最佳实践、性能陷阱
compose-multiplatform-patterns KMP 共享 UI Kotlin Multiplatform 共享 UI 层
android-clean-architecture Android 架构 Clean Architecture、KMP 模块划分

6.2 dart-flutter-patterns 核心

空安全(Null Safety)

Dart 的空安全系统是类型系统的一部分,dart-flutter-patterns 强调:

dart 复制代码
// 类型系统保证
String name;           // 不可空 --- 必须有值
String? nickname;      // 可空 --- 可以是 null
String title = '';     // 不可空 + 有默认值

// 空安全操作符
nickname?.toUpperCase()      // 空时返回 null
nickname ?? 'Anonymous'      // 空时用默认值
nickname!.toUpperCase()      // 断言非空(谨慎使用)

状态管理方案对比

方案 复杂度 适用场景 ECC 推荐度
setState 局部状态 仅限简单场景
Provider 中型应用 推荐
Riverpod 中高 中大型应用 强烈推荐
BLoC 大型应用 企业级推荐

Widget 架构

dart 复制代码
// Anti-Pattern: 深层嵌套
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            Container(
              decoration: BoxDecoration(...),
              child: Row(
                children: [
                  // 已经 6 层嵌套了...
                ],
              ),
            ),
          ],
        ),
      ),
    ),
  );
}

// 正确做法:提取子 Widget
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: Padding(
        padding: EdgeInsets.all(16),
        child: _ContentColumn(),
      ),
    ),
  );
}

6.3 GoRouter 导航

dart-flutter-patterns 推荐 GoRouter 作为导航方案:

dart 复制代码
final router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomeScreen(),
      routes: [
        GoRoute(
          path: 'users/:id',
          builder: (context, state) {
            final id = state.pathParameters['id']!;
            return UserDetailScreen(userId: id);
          },
        ),
      ],
    ),
  ],
);

七、跨平台方案对比

7.1 Flutter vs Compose Multiplatform

ECC 同时提供了两种跨平台方案的 Skill:

维度 Flutter (dart-flutter-patterns) KMP (compose-multiplatform-patterns)
语言 Dart Kotlin
UI 引擎 自绘引擎(Skia/Impeller) 平台原生 + Compose
代码共享 UI + 逻辑全共享 逻辑共享,UI 可选共享
平台 iOS, Android, Web, Desktop iOS, Android, Desktop, Web
学习曲线 中等 已有 Kotlin 经验则较低
ECC Agent flutter-reviewer, dart-build-resolver kotlin-reviewer, kotlin-build-resolver

7.2 android-clean-architecture

android-clean-architecture Skill 定义了 Android 项目的分层架构:

scss 复制代码
┌─────────────────────────┐
│  Presentation Layer     │  ← UI + ViewModel
│  (Android/Compose)      │
├─────────────────────────┤
│  Domain Layer           │  ← Use Cases + Entities
│  (Pure Kotlin)          │     无框架依赖
├─────────────────────────┤
│  Data Layer             │  ← Repository 实现
│  (Room/Retrofit/etc.)   │     + Data Sources
└─────────────────────────┘

关键原则:Domain Layer 是纯 Kotlin,不依赖任何 Android 框架。这使得业务逻辑可以在 KMP 项目中跨平台共享。


八、移动端 Anti-Patterns 分析

8.1 SwiftUI Anti-Patterns

Anti-Pattern 问题 正确做法
God View 一个视图超过 300 行 拆分为 Screen → Section → Component
过度使用 @State 所有状态都放在视图里 提取到 @Observable ViewModel
忽略 Actor 隔离 在主线程做耗时操作 使用 Actor 或 Task.detached
强制解包 到处使用 ! 使用 guard letif let
忽略生命周期 不清理 Task 使用 .task modifier 自动管理

8.2 Flutter Anti-Patterns

Anti-Pattern 问题 正确做法
深层嵌套 Widget 嵌套超过 5 层 提取子 Widget 或自定义 Widget
setState 滥用 在大型应用中用 setState 使用 Riverpod 或 BLoC
阻塞 UI 线程 在 build 方法中做计算 使用 compute() 或 Isolate
不使用 const 每次 build 创建新 Widget 尽可能使用 const 构造器
忽略 Key 列表不使用 Key 为列表项提供唯一 Key

九、本课练习

练习 1:查看移动端 Skill(10 分钟)

bash 复制代码
# Swift 生态
ls skills/swiftui-patterns/
ls skills/swift-concurrency-6-2/

# Flutter 生态
ls skills/dart-flutter-patterns/

回答问题:

  • swiftui-patterns 中关于 @Observable 的章节在哪里?
  • dart-flutter-patterns 推荐了哪些状态管理方案?

练习 2:分析 Anti-Patterns(20 分钟)

这是本课最重要的练习。

选择一个移动端 Skill(如 swiftui-patternsdart-flutter-patterns),找到其中描述的 Anti-Patterns 部分。

对每个 Anti-Pattern:

  1. 用自己的话解释为什么它是问题
  2. 写出正确做法的伪代码
  3. 思考在你的项目中是否存在类似问题

练习 3:对比导航方案(15 分钟)

对比 SwiftUI 的 NavigationStack 和 Flutter 的 GoRouter:

  • 它们的路由定义方式有什么相似之处?
  • 深层链接(Deep Link)的处理方式有什么差异?

练习 4(选做):思考题

设备端 LLM(foundation-models-on-device)适合哪些移动应用场景?不适合哪些?限制因素是什么?


十、本课小结

你应该记住的 内容
Swift 生态 5 个 Skill,从 SwiftUI 到设备端 LLM
核心变化 Swift 6.2 默认单线程,@concurrent 显式并发
Flutter 生态 4 个 Skill,含跨平台 KMP 方案
Anti-Patterns SwiftUI 的 God View,Flutter 的深层嵌套
跨平台选择 Flutter 全共享 vs KMP 逻辑共享

十一、下节预告

第 20 课:数据库模式 --- 设计、迁移与优化

下节课我们将进入数据层。你将学习 PostgreSQL 查询优化、零停机数据库迁移、以及 ECC 的 database-reviewer Agent 如何帮你避免 N+1 查询和不安全的 Schema 变更。

预习建议 :提前浏览 skills/postgres-patternsskills/database-migrations 目录。

相关推荐
王小酱3 小时前
第 26 课:Eval 驱动开发 — 衡量 AI 行为
ai编程
王小酱3 小时前
第 25 课:持续学习 — Instinct 提取与演化
ai编程
王小酱3 小时前
第 20 课:数据库模式 — 设计、迁移与优化
ai编程
王小酱3 小时前
第 24 课:安全(下)— 防御机制与实战
ai编程
王小酱3 小时前
第 10 课:Hooks — 事件驱动自动化
openai·ai编程·aiops
王小酱3 小时前
第 16 课:多代理编排 — 并行、视角与隔离
openai·ai编程
王小酱3 小时前
第 15 课:会话管理 — 上下文、模型与持久化
openai·ai编程·aiops
王小酱3 小时前
第 27 课:Agent 工程与 LLM 成本优化
ai编程
王小酱3 小时前
第 11 课:Scripts — Hook 的底层实现
openai·ai编程·aiops