在实际开发中,App 常常需要从远程服务器获取数据并展示给用户。本章将介绍在 SwiftUI 中如何优雅地处理网络请求与 JSON 解析,包括:
使用原生
URLSession
的方式(用于入门和底层理解)实际项目中更常用的第三方库 Alamofire
如何将请求逻辑与 SwiftUI 的视图进行解耦(MVVM 架构)
一、使用 URLSession 加载数据(了解底层原理)
URLSession
是苹果提供的原生网络 API,适合理解网络请求的基本流程:
func fetchData(from urlString: String, completion: @escaping (Data?) -> Void) {
guard let url = URL(string: urlString) else {
completion(nil)
return
}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print("请求失败:\(error)")
completion(nil)
} else {
completion(data)
}
}.resume()
}
二、定义模型并解析 JSON 数据
苹果提供了 Codable
协议用于自动解析 JSON 数据,非常方便。
struct Article: Codable, Identifiable {
let id: Int
let title: String
let author: String
}
func parseArticles(from data: Data) -> [Article]? {
let decoder = JSONDecoder()
do {
return try decoder.decode([Article].self, from: data)
} catch {
print("解析失败:\(error)")
return nil
}
}
三、使用 Alamofire 简化网络请求(推荐方式)
在真实开发中,为了减少样板代码并提高可维护性,推荐使用第三方网络库 Alamofire。
安装方式
使用 Swift Package Manager 集成:
https://github.com/Alamofire/Alamofire
使用示例
import Alamofire
func loadArticles(completion: @escaping ([Article]?) -> Void) {
AF.request("https://example.com/api/articles")
.validate()
.responseDecodable(of: [Article].self) { response in
switch response.result {
case .success(let articles):
completion(articles)
case .failure(let error):
print("请求失败:\(error)")
completion(nil)
}
}
}
四、ViewModel 统一管理网络请求与状态(MVVM 架构)
将网络请求逻辑封装在 ViewModel
中,便于状态管理和 SwiftUI 绑定。
class ArticleViewModel: ObservableObject {
@Published var articles: [Article] = []
@Published var isLoading = false
@Published var errorMessage: String?
func fetchArticles() {
isLoading = true
errorMessage = nil
loadArticles { [weak self] result in
DispatchQueue.main.async {
self?.isLoading = false
if let result = result {
self?.articles = result
} else {
self?.errorMessage = "加载失败"
}
}
}
}
}
五、构建绑定视图显示加载状态与数据
结合 SwiftUI 状态系统自动刷新界面:
struct ArticleListView: View {
@StateObject private var viewModel = ArticleViewModel()
var body: some View {
NavigationStack {
Group {
if viewModel.isLoading {
ProgressView("加载中...")
} else if let error = viewModel.errorMessage {
Text(error).foregroundColor(.red)
} else {
List(viewModel.articles) { article in
VStack(alignment: .leading, spacing: 4) {
Text(article.title)
.font(.headline)
Text("作者:\(article.author)")
.font(.subheadline)
.foregroundColor(.gray)
}
.padding(.vertical, 4)
}
}
}
.navigationTitle("文章列表")
.onAppear {
viewModel.fetchArticles()
}
}
}
}
六、总结
技术点 | 实践意义 |
---|---|
URLSession |
理解底层网络请求流程 |
Codable |
自动解析 JSON 数据,提高开发效率 |
Alamofire |
简化请求流程、处理错误、自动解码 |
ObservableObject |
管理异步状态并驱动视图刷新 |
SwiftUI 状态绑定 | 自动更新 UI,无需手动刷新 |