# APIClient 集成指南 ## 🔧 在其他文件中使用 APIClient ### 方法一:直接实例化 (推荐用于测试) ```swift import SwiftUI struct ContentView: View { @State private var isLoading = false @State private var result = "" var body: some View { VStack { Button("测试 API") { testAPI() } .disabled(isLoading) if isLoading { ProgressView("请求中...") } Text(result) } } private func testAPI() { isLoading = true Task { do { // 创建 API 客户端实例 let apiClient = LiveAPIClient( baseURL: URL(string: "https://your-api.com")! ) // 发起请求 let response: YourResponseModel = try await apiClient.get( path: "/your/endpoint", queryParameters: ["key": "value"] ) await MainActor.run { result = "成功: \(response)" isLoading = false } } catch { await MainActor.run { result = "错误: \(error.localizedDescription)" isLoading = false } } } } } ``` ### 方法二:使用单例模式 ```swift // 在需要使用的文件中 private func makeAPIRequest() async { do { let response: SomeModel = try await APIClientManager.shared.get( path: "/endpoint" ) // 处理响应 } catch { // 处理错误 } } ``` ### 方法三:TCA 集成 (当 TCA 可用时) ```swift import ComposableArchitecture @Reducer struct MyFeature { @ObservableState struct State: Equatable { var data: [Item] = [] var isLoading = false } enum Action: Equatable { case loadData case dataLoaded([Item]) case loadingFailed(String) } @Dependency(\.apiClient) var apiClient var body: some ReducerOf { Reduce { state, action in switch action { case .loadData: state.isLoading = true return .run { send in do { let items: [Item] = try await apiClient.get(path: "/items") await send(.dataLoaded(items)) } catch { await send(.loadingFailed(error.localizedDescription)) } } case let .dataLoaded(items): state.isLoading = false state.data = items return .none case let .loadingFailed(error): state.isLoading = false // 处理错误 return .none } } } } ``` ## 🚨 常见问题解决 ### 1. "Cannot find 'APIClientManager' in scope" **原因**: Swift 模块系统问题,需要确保正确导入 **解决方案**: ```swift // 方案 A: 直接实例化 let apiClient = LiveAPIClient(baseURL: URL(string: "https://api.com")!) // 方案 B: 确保文件在同一个 target 中 // 检查 Xcode 项目设置,确保 APICaller.swift 和使用文件在同一个 target // 方案 C: 使用原生 URLSession (临时方案) let (data, _) = try await URLSession.shared.data(for: request) ``` ### 2. TCA 导入问题 **原因**: ComposableArchitecture 模块配置问题 **解决方案**: 1. 检查 Package Dependencies 是否正确添加 2. 确保 target 正确链接了 TCA 3. Clean Build Folder (⌘+Shift+K) 4. 重新构建项目 ### 3. 网络请求失败 **常见错误处理**: ```swift do { let response = try await apiClient.get(path: "/endpoint") // 成功处理 } catch let urlError as URLError { switch urlError.code { case .notConnectedToInternet: print("网络不可用") case .timedOut: print("请求超时") case .cannotFindHost: print("无法找到服务器") default: print("网络错误: \(urlError.localizedDescription)") } } catch { print("其他错误: \(error)") } ``` ## 📝 最佳实践 1. **错误处理**: 始终使用 do-catch 处理异步请求 2. **主线程更新**: 使用 `await MainActor.run` 更新 UI 3. **取消请求**: 在适当时候取消不需要的请求 4. **重试机制**: 对于网络错误实现重试逻辑 5. **缓存策略**: 考虑实现适当的缓存机制 ## 🔄 迁移步骤 从原生 URLSession 迁移到 APIClient: 1. **保留现有代码** - 确保功能正常 2. **逐步替换** - 一个接口一个接口地迁移 3. **测试验证** - 每次迁移后进行测试 4. **清理代码** - 移除不需要的原生实现 这样可以确保平滑的迁移过程,避免破坏现有功能。