30天学会Swift-28:SwiftUI-网络请求与JSON解析
本文介绍了在SwiftUI应用中实现网络请求的方法。主要内容包括:使用URLSession进行HTTP请求、通过Codable协议解析JSON数据、处理异步操作(async/await)以及在视图中展示网络数据。文章提供了创建API服务类、定义数据模型、执行网络请求和错误处理的完整代码示例,并展示了如何在SwiftUI视图中绑定和显示数据。同时介绍了POST请求的编码实现,帮助开发者全面掌握iOS
·
学习目标
- 理解如何在SwiftUI应用中进行网络请求。
- 掌握使用
URLSession
进行数据请求。 - 学习如何使用
Codable
协议进行JSON数据的编码和解码。 - 了解异步网络请求的处理。
- 掌握如何在视图中显示从网络获取的数据。
学习内容
1. 网络请求基础
在Swift中,进行网络请求最常用的框架是URLSession
。它提供了丰富的功能来处理HTTP/HTTPS请求。
1.1 URLSession
URLSession
是Apple提供的用于处理网络请求的API。它支持数据任务(dataTask
)、下载任务(downloadTask
)和上传任务(uploadTask
)。
2. Codable
协议 (JSON解析)
Codable
是Encodable
和Decodable
协议的类型别名。它允许你轻松地将自定义数据类型与JSON等外部表示进行相互转换。
2.1 定义可编码/解码的数据模型
// 定义一个符合Codable协议的结构体,用于解析JSON数据
struct Post: Codable, Identifiable {
let id: Int
let userId: Int
let title: String
let body: String
}
// 如果JSON键名与属性名不一致,可以使用CodingKeys
struct User: Codable, Identifiable {
let id: Int
let name: String
let email: String
enum CodingKeys: String, CodingKey {
case id
case name = "username" // JSON中的"username"对应Swift中的name
case email
}
}
3. 执行网络请求和JSON解析
通常,网络请求会在一个单独的服务或管理器类中进行,以保持视图的简洁。
import Foundation
class APIService: ObservableObject {
@Published var posts: [Post] = []
@Published var isLoading = false
@Published var errorMessage: String? = nil
func fetchPosts() async {
isLoading = true
errorMessage = nil
guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else {
errorMessage = "Invalid URL"
isLoading = false
return
}
do {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
errorMessage = "Server error or invalid response"
isLoading = false
return
}
let decodedPosts = try JSONDecoder().decode([Post].self, from: data)
DispatchQueue.main.async {
self.posts = decodedPosts
self.isLoading = false
}
} catch {
DispatchQueue.main.async {
self.errorMessage = "Failed to fetch posts: \(error.localizedDescription)"
self.isLoading = false
}
}
}
}
4. 在SwiftUI视图中显示数据
使用@StateObject
或@ObservedObject
来监听APIService
的变化,并在视图中显示数据。
import SwiftUI
struct PostListView: View {
@StateObject private var apiService = APIService()
var body: some View {
NavigationView {
VStack {
if apiService.isLoading {
ProgressView("Loading Posts...")
} else if let error = apiService.errorMessage {
Text("Error: \(error)")
.foregroundColor(.red)
} else {
List(apiService.posts) {
post in
VStack(alignment: .leading) {
Text(post.title)
.font(.headline)
Text(post.body)
.font(.subheadline)
.foregroundColor(.gray)
}
}
}
}
.navigationTitle("Posts")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Refresh") {
Task {
await apiService.fetchPosts()
}
}
}
}
.onAppear {
// 在视图出现时加载数据
Task {
await apiService.fetchPosts()
}
}
}
}
}
5. 处理异步操作 (async/await
)
Swift 5.5引入的async/await
语法极大地简化了异步代码的编写。URLSession
的data(from:)
方法现在支持async/await
。
- 在调用异步函数时使用
await
。 - 在需要执行异步操作的函数前加上
async
。 - 在
Task
闭包中调用异步函数。
6. 错误处理
在网络请求中,错误处理至关重要。使用do-catch
块来捕获可能发生的错误,例如网络连接问题、无效URL、服务器响应错误或JSON解析失败。
7. 数据编码 (JSONEncoder
)
除了解码,Codable
也支持编码,将Swift对象转换为JSON数据,常用于发送POST/PUT请求。
struct NewPost: Codable {
let title: String
let body: String
let userId: Int
}
func createPost(newPost: NewPost) async throws -> Post {
guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else {
throw URLError(.badURL)
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let encoder = JSONEncoder()
request.httpBody = try encoder.encode(newPost)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 201 else {
throw URLError(.badServerResponse)
}
let createdPost = try JSONDecoder().decode(Post.self, from: data)
return createdPost
}
实践练习
- 获取并显示用户列表:
- 使用
https://jsonplaceholder.typicode.com/users
作为API端点。 - 定义一个
User
结构体,包含id
,name
,email
等属性,并使其符合Codable
。 - 创建一个
UserService
类,负责获取用户数据。 - 在SwiftUI视图中显示用户列表,点击用户可以显示其详细信息。
- 使用
- 发送POST请求:
- 创建一个简单的表单,包含标题和内容输入框。
- 当用户点击提交按钮时,将表单数据编码为JSON,并发送POST请求到
https://jsonplaceholder.typicode.com/posts
。 - 显示服务器返回的响应(例如新创建的帖子的ID)。
- 错误处理与UI反馈:
- 在网络请求中模拟网络错误(例如,尝试请求一个不存在的URL)。
- 在UI中显示友好的错误消息,并提供重试按钮。
思考题
- 在实际项目中,你会如何组织网络请求代码,例如使用单例模式、依赖注入还是其他模式?
- 如何处理网络请求中的认证(例如Bearer Token)?
- 如何实现图片懒加载和缓存,以优化网络性能和用户体验?
更多推荐
所有评论(0)