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 章:构建一个小型应用

联系人管理 (Contact Manager)

项目概述

在本实战项目中,我们将使用 SwiftData 构建一个完整的联系人管理应用。该应用将实现以下核心功能:

  • 添加/编辑联系人信息(姓名、电话、邮箱、地址等)
  • 按姓名或分组筛选联系人
  • 收藏常用联系人
  • 支持联系人照片存储
  • 数据持久化与自动同步(若启用 CloudKit)

1. 数据模型设计

import SwiftData
import SwiftUI

@Model
final class Contact {
    var id: UUID
    var name: String
    var phone: String?
    var email: String?
    var address: String?
    var isFavorite: Bool
    var createdAt: Date
    var group: ContactGroup?
    var photoData: Data?
    
    init(name: String, phone: String? = nil, email: String? = nil) {
        self.id = UUID()
        self.name = name
        self.phone = phone
        self.email = email
        self.isFavorite = false
        self.createdAt = Date()
    }
}

@Model
final class ContactGroup {
    var name: String
    @Relationship(deleteRule: .nullify) var contacts: [Contact]
    
    init(name: String) {
        self.name = name
        self.contacts = []
    }
}

2. 核心功能实现

2.1 联系人列表视图

struct ContactListView: View {
    @Query(sort: \Contact.name) private var contacts: [Contact]
    @Environment(\.modelContext) private var context
    
    var body: some View {
        List {
            ForEach(contacts) { contact in
                NavigationLink {
                    ContactDetailView(contact: contact)
                } label: {
                    ContactRowView(contact: contact)
                }
            }
            .onDelete(perform: deleteContacts)
        }
        .toolbar {
            Button("Add", systemImage: "plus") {
                context.insert(Contact(name: "New Contact"))
            }
        }
    }
    
    private func deleteContacts(_ indexSet: IndexSet) {
        for index in indexSet {
            context.delete(contacts[index])
        }
    }
}

2.2 联系人详情与编辑

struct ContactDetailView: View {
    @Bindable var contact: Contact
    @State private var isEditing = false
    
    var body: some View {
        Form {
            if let photoData = contact.photoData, let image = UIImage(data: photoData) {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(height: 150)
            }
            
            Section("Basic Info") {
                TextField("Name", text: $contact.name)
                TextField("Phone", text: $contact.phone ?? "")
                TextField("Email", text: $contact.email ?? "")
            }
            
            Section("Additional") {
                TextField("Address", text: $contact.address ?? "")
                Toggle("Favorite", isOn: $contact.isFavorite)
            }
        }
        .navigationTitle(contact.name)
    }
}

3. 高级功能实现

3.1 分组管理

struct ContactGroupView: View {
    @Query(sort: \ContactGroup.name) var groups: [ContactGroup]
    @Environment(\.modelContext) var context
    
    var body: some View {
        List {
            ForEach(groups) { group in
                NavigationLink(group.name) {
                    GroupContactListView(group: group)
                }
            }
            .onDelete(perform: deleteGroups)
        }
        .toolbar {
            Button("New Group") {
                context.insert(ContactGroup(name: "New Group"))
            }
        }
    }
    
    private func deleteGroups(_ indexSet: IndexSet) {
        indexSet.forEach { index in
            context.delete(groups[index])
        }
    }
}

3.2 搜索与筛选

struct ContactSearchView: View {
    @State private var searchText = ""
    @State private var showFavoritesOnly = false
    
    var body: some View {
        NavigationStack {
            ContactListView(
                predicate: searchPredicate,
                sortOrder: [SortDescriptor(\Contact.name)]
            )
            .searchable(text: $searchText)
            .toolbar {
                Toggle("Favorites Only", isOn: $showFavoritesOnly)
            }
        }
    }
    
    private var searchPredicate: Predicate<Contact>? {
        var predicates: [Predicate<Contact>] = []
        
        if !searchText.isEmpty {
            predicates.append(
                #Predicate { contact in
                    contact.name.localizedStandardContains(searchText) ||
                    contact.phone?.contains(searchText) == true ||
                    contact.email?.contains(searchText) == true
                }
            )
        }
        
        if showFavoritesOnly {
            predicates.append(#Predicate { $0.isFavorite })
        }
        
        return predicates.isEmpty ? nil : predicates.reduce(Predicate { _ in true }) { partialResult, predicate in
            partialResult && predicate
        }
    }
}

4. 数据持久化配置

@main
struct ContactManagerApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: [Contact.self, ContactGroup.self])
    }
}

5. 项目扩展建议

  1. 照片处理:添加相机/相册集成功能
  2. 云同步:启用 CloudKit 实现跨设备同步
  3. 导入/导出:支持 vCard 格式导入导出
  4. 快捷操作:添加主屏幕快捷操作
  5. Widgets:开发常用联系人小组件

6. 调试技巧

// 在应用启动时添加示例数据
struct ExampleDataViewModifier: ViewModifier {
    @Environment(\.modelContext) private var context
    
    func body(content: Content) -> some View {
        content
            .task {
                guard try? context.fetch(FetchDescriptor<Contact>()).isEmpty else { return }
                
                let groups = [
                    ContactGroup(name: "Family"),
                    ContactGroup(name: "Work"),
                    ContactGroup(name: "Friends")
                ]
                
                let contacts = [
                    Contact(name: "John Appleseed", phone: "555-123-4567", email: "john@example.com"),
                    Contact(name: "Kate Bell", phone: "555-234-5678", email: "kate@example.com"),
                    Contact(name: "Anna Haro", phone: "555-345-6789", email: "anna@example.com")
                ]
                
                contacts[0].group = groups[0]
                contacts[1].group = groups[1]
                contacts[2].group = groups[2]
                
                groups.forEach { context.insert($0) }
                contacts.forEach { context.insert($0) }
            }
    }
}

7. 项目结构建议

ContactManager/
├── Models/
│   ├── Contact.swift
│   └── ContactGroup.swift
├── Views/
│   ├── ContactListView.swift
│   ├── ContactDetailView.swift
│   ├── ContactRowView.swift
│   ├── ContactGroupView.swift
│   └── GroupContactListView.swift
├── Utilities/
│   ├── PredicateBuilder.swift
│   └── ExampleData.swift
└── ContactManagerApp.swift

通过这个完整的联系人管理项目,您将掌握 SwiftData 在实际应用中的综合运用,包括数据模型设计、关系管理、查询优化和 UI 集成等关键技能。

Last Updated:: 5/30/25, 5:48 PM