Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 第 14 章:构建一个小型应用

第 14 章:构建一个小型应用

笔记应用 (Note App)

项目概述

本节将指导你使用 SwiftData 构建一个功能完整的笔记应用,包含以下核心功能:

  • 创建/编辑/删除笔记
  • 富文本内容支持(标题+正文)
  • 分类标签管理
  • 搜索功能
  • 数据持久化与自动同步

1. 数据模型设计

@Model
final class Note {
    var title: String
    var content: String
    var createdAt: Date
    var updatedAt: Date
    var isPinned: Bool
    @Relationship(deleteRule: .nullify) var tags: [Tag]
    
    init(title: String, content: String) {
        self.title = title
        self.content = content
        self.createdAt = .now
        self.updatedAt = .now
        self.isPinned = false
    }
}

@Model
final class Tag {
    var name: String
    var notes: [Note]
    
    init(name: String) {
        self.name = name
    }
}

2. 核心功能实现

初始化 ModelContainer

struct NotesApp: App {
    let container = ModelContainer(
        for: [Note.self, Tag.self],
        configurations: ModelConfiguration(isStoredInMemoryOnly: false)
    )
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(container)
    }
}

笔记列表视图

struct NotesListView: View {
    @Query(sort: \Note.updatedAt, order: .reverse) var notes: [Note]
    @Environment(\.modelContext) private var context
    
    var body: some View {
        List {
            ForEach(notes) { note in
                NavigationLink {
                    NoteEditorView(note: note)
                } label: {
                    VStack(alignment: .leading) {
                        Text(note.title).font(.headline)
                        Text(note.content.prefix(50)).font(.subheadline)
                    }
                }
            }
            .onDelete { indexes in
                indexes.forEach { index in
                    context.delete(notes[index])
                }
            }
        }
        .toolbar {
            Button("Add") {
                let newNote = Note(title: "New Note", content: "")
                context.insert(newNote)
            }
        }
    }
}

笔记编辑器

struct NoteEditorView: View {
    @Bindable var note: Note
    @State private var newTagName = ""
    
    var body: some View {
        Form {
            TextField("Title", text: $note.title)
            TextEditor(text: $note.content)
                .frame(minHeight: 200)
            
            Section("Tags") {
                ForEach(note.tags) { tag in
                    Text(tag.name)
                }
                HStack {
                    TextField("Add Tag", text: $newTagName)
                    Button("Add") {
                        let tag = Tag(name: newTagName)
                        note.tags.append(tag)
                        newTagName = ""
                    }
                }
            }
        }
        .onDisappear {
            note.updatedAt = .now
        }
    }
}

3. 高级功能扩展

搜索实现

@Query var allNotes: [Note]

func searchNotes(_ text: String) -> [Note] {
    guard !text.isEmpty else { return allNotes }
    
    let predicate = #Predicate<Note> { note in
        note.title.localizedStandardContains(text) ||
        note.content.localizedStandardContains(text)
    }
    
    return (try? allNotes.filter(predicate)) ?? []
}

自动保存策略

// 在 App 启动时设置自动保存
.container = ModelContainer(
    for: Note.self,
    configurations: ModelConfiguration(
        isAutosaveEnabled: true
    )
)

4. 项目优化建议

  1. 性能优化:

    • 对长内容笔记实现分页加载
    • 使用 @Query 的 animation 参数实现平滑过渡
  2. 用户体验:

    • 添加 Markdown 预览功能
    • 实现笔记版本历史(需扩展数据模型)
  3. 数据安全:

    • 添加本地加密功能(对 Data 类型属性使用加密转换)
    • 实现回收站机制(软删除模式)

5. 完整项目结构建议

NotesApp/
├── Models/
│   ├── Note.swift
│   └── Tag.swift
├── Views/
│   ├── NotesListView.swift
│   ├── NoteEditorView.swift
│   └── TagManagerView.swift
├── Utilities/
│   ├── SearchUtility.swift
│   └── AutoSaver.swift
└── NotesApp.swift

下一步挑战

尝试为应用添加以下功能:

  1. 笔记导出为 PDF 功能
  2. 基于标签的智能文件夹
  3. 与 CloudKit 的同步集成
  4. 多设备间的手势冲突解决
Last Updated:: 5/30/25, 5:48 PM