SwiftUI中的网络请求最佳实践
纯想的APIKEY: e1300567e653b2e517e66f609d006e42
info里添加: App Transport Security Settings -> Allow Arbitrary Loads -> YES
HTTP协议发展史
HTTP协议经历了多个版本的演进,从最初的0.9到现在的HTTP/3。
- Name
发展历程
- Type
- history
- Description
- HTTP/0.9(1991): 仅支持GET方法,纯文本传输
- HTTP/1.0(1996): 增加POST等方法,支持多媒体
- HTTP/1.1(1997): 持久连接,管道机制
- HTTP/2(2015): 多路复用,服务器推送
- HTTP/3(2022): 基于QUIC协议,更快更安全
- Name
核心特性
- Type
- features
- Description
- 无状态性: 每次请求相互独立
- 可扩展性: 自定义头部字段
- 可靠性: 基于TCP/IP协议
- 简单性: 人类可读的文本格式
HTTP基础概念
// HTTP请求的组成部分
struct HTTPComponents {
// 请求行
let method: String // 请求方法
let path: String // 资源路径
let version: String // 协议版本
// 请求头
var headers: [String: String] = [
"Accept": "*/*",
"User-Agent": "SwiftUI/1.0"
]
// 请求体
var body: Data?
}
现代网络请求架构
在SwiftUI应用中,我们需要一个优雅且健壮的网络层。
- Name
设计原则
- Type
- principles
- Description
- 职责分离: 网络层与业务逻辑解耦
- 错误处理: 统一的错误处理机制
- 可测试性: 易于编写单元测试
- 类型安全: 利用Swift的类型系统
- Name
最佳实践
- Type
- practices
- Description
- 使用async/await替代回调
- 采用面向协议的设计
- 实现请求重试机制
- 处理网络状态变化
现代网络层实现
// 定义网络错误类型
enum NetworkError: Error {
case invalidURL
case requestFailed(Int)
case decodingFailed
case noInternet
}
// 网络服务协议
protocol NetworkServiceType {
func request<T: Decodable>(
endpoint: String,
method: String,
body: Data?
) async throws -> T
}
// 具体实现
class NetworkService: NetworkServiceType {
private let baseURL = "https://api.example.com"
private let session: URLSession
init(session: URLSession = .shared) {
self.session = session
}
func request<T: Decodable>(
endpoint: String,
method: String = "GET",
body: Data? = nil
) async throws -> T {
guard let url = URL(string: "\(baseURL)/\(endpoint)") else {
throw NetworkError.invalidURL
}
var request = URLRequest(url: url)
request.httpMethod = method
request.httpBody = body
let (data, response) = try await session.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw NetworkError.requestFailed(0)
}
guard (200...299).contains(httpResponse.statusCode) else {
throw NetworkError.requestFailed(httpResponse.statusCode)
}
do {
return try JSONDecoder().decode(T.self, from: data)
} catch {
throw NetworkError.decodingFailed
}
}
}
SwiftUI集成实践
在SwiftUI中优雅地处理网络请求和UI状态。
- Name
架构特点
- Type
- features
- Description
- MVVM架构模式
- 响应式状态管理
- 优雅的错误处理
- 用户友好的加载状态
- Name
关键技术
- Type
- techniques
- Description
- @Published属性包装器
- async/await异步操作
- 错误提示UI组件
- 加载状态指示器
SwiftUI集成示例
// 数据模型
struct Article: Codable, Identifiable {
let id: Int
let title: String
let content: String
let author: String
let publishDate: Date
}
// ViewModel
@MainActor
class ArticleViewModel: ObservableObject {
@Published private(set) var articles: [Article] = []
@Published private(set) var isLoading = false
@Published private(set) var error: NetworkError?
private let service: NetworkServiceType
init(service: NetworkServiceType = NetworkService()) {
self.service = service
}
func fetchArticles() async {
isLoading = true
defer { isLoading = false }
do {
articles = try await service.request(endpoint: "articles")
error = nil
} catch let error as NetworkError {
self.error = error
} catch {
self.error = .requestFailed(0)
}
}
}
// View
struct ArticleListView: View {
@StateObject private var viewModel = ArticleViewModel()
var body: some View {
NavigationView {
List(viewModel.articles) { article in
VStack(alignment: .leading) {
Text(article.title)
.font(.headline)
Text(article.author)
.font(.subheadline)
.foregroundColor(.secondary)
}
}
.overlay {
if viewModel.isLoading {
ProgressView()
}
}
.refreshable {
await viewModel.fetchArticles()
}
.alert(
"网络错误",
isPresented: .constant(viewModel.error != nil)
) {
Button("重试") {
Task {
await viewModel.fetchArticles()
}
}
} message: {
Text(viewModel.error?.localizedDescription ?? "")
}
.navigationTitle("文章列表")
}
.task {
await viewModel.fetchArticles()
}
}
}