feat: 添加Swift Package管理和API功能模块
新增Package.swift和Package.resolved文件以支持Swift Package管理,创建API相关文件(API.swift、APICaller.swift、APIConstants.swift、APIEndpoints.swift、APIService.swift、APILogger.swift、APIModels.swift、Integration-Guide.md)以实现API请求管理和网络交互功能,增强项目的功能性和可扩展性。同时更新.gitignore以排除构建文件和临时文件。
This commit is contained in:
196
yana/APIs/Integration-Guide.md
Normal file
196
yana/APIs/Integration-Guide.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# 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<Self> {
|
||||
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. **清理代码** - 移除不需要的原生实现
|
||||
|
||||
这样可以确保平滑的迁移过程,避免破坏现有功能。
|
Reference in New Issue
Block a user