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
  • 数据持久化与网络请求

数据持久化与网络请求

概述

在 MVVM 架构中,Model 层负责数据的持久化存储和远程数据获取。本章将介绍如何在 SwiftUI 的 MVVM 架构中实现这两大核心功能。

数据持久化方案

1. UserDefaults

  • 适用场景:小型配置数据或用户偏好设置
  • 实现方式:
    // 存储
    UserDefaults.standard.set(value, forKey: "key")
    
    // 读取
    let value = UserDefaults.standard.string(forKey: "key")
    
  • 注意事项:
    • 不适合存储大量数据
    • 非线程安全,需在主线程操作

2. Core Data

  • SwiftUI 集成:
    @Environment(\.managedObjectContext) private var viewContext
    
  • 最佳实践:
    • 使用 NSManagedObject 子类作为 Model
    • 通过 @FetchRequest 属性包装器实现数据绑定

3. 文件系统存储

  • JSON 编码/解码:
    struct Todo: Codable { ... }
    
    // 编码存储
    let data = try JSONEncoder().encode(todos)
    try data.write(to: fileURL)
    
    // 解码读取
    let data = try Data(contentsOf: fileURL)
    let todos = try JSONDecoder().decode([Todo].self, from: data)
    

网络请求实现

1. URLSession 基础

func fetchTodos() async throws -> [Todo] {
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode([Todo].self, from: data)
}

2. 结合 Combine 框架

class TodoService: ObservableObject {
    @Published var todos: [Todo] = []
    private var cancellables = Set<AnyCancellable>()
    
    func loadTodos() {
        URLSession.shared.dataTaskPublisher(for: url)
            .map(\.data)
            .decode(type: [Todo].self, decoder: JSONDecoder())
            .receive(on: DispatchQueue.main)
            .sink(receiveCompletion: { _ in },
                  receiveValue: { [weak self] in self?.todos = $0 })
            .store(in: &cancellables)
    }
}

3. 错误处理策略

  • 网络层错误分类:
    enum NetworkError: Error {
        case invalidURL
        case requestFailed(Error)
        case invalidResponse
        case decodingFailed(Error)
    }
    
  • 重试机制:
    .retry(3)
    .catch { error in
        Just([]) // 返回空数组作为降级方案
    }
    

MVVM 中的实现模式

1. 服务层抽象

protocol DataServiceProtocol {
    func fetchTodos() async throws -> [Todo]
    func saveTodos(_ todos: [Todo]) async throws
}

class TodoRepository: DataServiceProtocol {
    // 实现具体逻辑
}

2. ViewModel 集成

class TodoListViewModel: ObservableObject {
    @Published private(set) var todos: [Todo] = []
    private let service: DataServiceProtocol
    
    init(service: DataServiceProtocol = TodoRepository()) {
        self.service = service
    }
    
    @MainActor
    func loadTodos() async {
        do {
            todos = try await service.fetchTodos()
        } catch {
            // 处理错误
        }
    }
}

实战案例:Todo 应用的持久化方案

1. 完整实现流程

  1. 定义 Todo 模型实现 Codable 协议
  2. 创建 TodoPersistenceService 处理本地存储
  3. 开发 TodoAPIService 处理网络请求
  4. 在 ViewModel 中协调两种数据源

2. 数据同步策略

func syncData() async {
    // 1. 从网络获取最新数据
    let remoteTodos = try? await apiService.fetchTodos()
    
    // 2. 与本地数据合并
    let mergedTodos = merge(local: localTodos, remote: remoteTodos)
    
    // 3. 保存到本地
    try? await persistenceService.save(mergedTodos)
    
    // 4. 更新 ViewModel
    await MainActor.run {
        self.todos = mergedTodos
    }
}

性能优化建议

  1. 网络请求优化:

    • 使用缓存策略(URLCache)
    • 实现分页加载(offset/limit)
  2. 持久化优化:

    • 批量写入操作
    • 后台上下文处理耗时操作
  3. 线程安全:

    • 确保 Core Data 操作在正确的上下文中执行
    • 使用 @MainActor 标注 UI 更新方法
Last Updated:: 4/25/25, 8:06 PM