有.NET背景,如何从Alamofire返回ViewModel格式的数据?
关于SwiftUI中使用Alamofire处理API请求并转换为ViewModel的问题
我是SwiftUI新手,正在学习使用Alamofire进行API调用。我有C#开发背景,若代码存在问题还请见谅。我编写了一个调用API的类,了解到需要用完成处理程序(completion handler)来处理异步返回的数据,但不确定如何正确提取JSON并转为ViewModel。
我的API调用类代码
class webapilib{ var apiURLBase = "https://secreturl.com/api/" init() { } func getFriends(completionHandler: ) { performRequest() } func performRequest () { let request = apiURLBase var url = request + "Friends/GetAllParentsFriends?parentId=1" AF.request(url).responseData { response in switch response.result { case .success(let value): return String(data: value) case .failure(let error): print(error) } }
API返回的数据示例
{"parents":[{"id":1,"type":null,"firstName":"Murry","groupId":null,"children":null,"emmailAddress":null,"surname":"Goldberg","name":null,"isParent":null,"isDeleted":false,"isActive":true,"createdBy":null,"lastModifiedBy":null,"lastUpdatedDate":null,"createdDate":null}],"children":[{"id":24864,"type":null,"orginizationId":null,"personId":null,"coachId":null,"teamId":null,"playerLevel":"A","fullName":"Audrey Lind","firstName":"Audrey","surname":"Lind","year":2008,"weight":null,"gender":null,"photo":null,"orgId":null,"ageGroup":null,"age":null,"emailAddress":"tandklind@msn.com","conditioningWorkouts":null,"conditioningWorkout":null,"bookings":null,"bikeWorkOuts":null,"isDeleted":false,"notes":null,"defaultTB":150.00,"defaultOP":15.00,"defaultPU":0.00,"defaultPB":null,"defaultBP":15.00,"defaultTBReps":5.00,"defaultOPReps":0.00,"defaultPUReps":10.00,"defaultPBReps":null,"defaultBPReps":0.00,"defaultAdvancedPuReps":0.00,"defaultAdvancedPu":0.00,"defaultPuSeconds":null,"defaultBroadJumpFeet":null,"defaultBroadJumpInches":null,"defaultTwentyFiveYards":null,"defaultOneFityYards":null,"status":0,"isActive":true,"createdBy":"System Import","lastModifiedBy":"Brandon","lastUpdatedDate":"2022-03-29T15:00:28.944125","createdDate":"2021-12-17T01:07:01.1819126"},{"id":24866,"type":null,"orginizationId":null,"personId":null,"coachId":null,"teamId":null,"playerLevel":"A","fullName":"Ellarae Atkinson","firstName":"Ellarae","surname":"Atkinson","year":2009,"weight":null,"gender":null,"photo":null,"orgId":null,"ageGroup":null,"age":null,"emailAddress":"atkinson_06@comcast.net","conditioningWorkouts":null,"conditioningWorkout":null,"bookings":null,"bikeWorkOuts":null,"isDeleted":false,"notes":null,"defaultTB":55.00,"defaultOP":20.00,"defaultPU":0.00,"defaultPB":null,"defaultBP":15.00,"defaultTBReps":2399.00,"defaultOPReps":0.00,"defaultPUReps":0.00,"defaultPBReps":null,"defaultBPReps":0.00,"defaultAdvancedPuReps":0.00,"defaultAdvancedPu":0.00,"defaultPuSeconds":null,"defaultBroadJumpFeet":null,"defaultBroadJumpInches":null,"defaultTwentyFiveYards":null,"defaultOneFityYards":null,"status":0,"isActive":true,"createdBy":"System Import","lastModifiedBy":null,"lastUpdatedDate":"2022-02-09T07:09:32.994522","createdDate":"2021-12-17T01:07:09.6571143"}]}
按钮调用API的代码
func callApi() { let api = thehockeylabapi().self let test: () = api.getFriends() }
Button("getFriends", action: callApi)
解决方案步骤
1. 定义对应JSON结构的Codable模型
根据返回的JSON结构,创建遵循Codable协议的Swift模型,用于自动解析JSON:
// 家长模型 struct Parent: Codable, Identifiable { let id: Int let type: String? let firstName: String? let groupId: Int? let children: [Child]? let emmailAddress: String? let surname: String? let name: String? let isParent: Bool? let isDeleted: Bool let isActive: Bool let createdBy: String? let lastModifiedBy: String? let lastUpdatedDate: String? let createdDate: String? } // 孩子模型 struct Child: Codable, Identifiable { let id: Int let type: String? let orginizationId: Int? let personId: Int? let coachId: Int? let teamId: Int? let playerLevel: String? let fullName: String? let firstName: String? let surname: String? let year: Int? let weight: Double? let gender: String? let photo: String? let orgId: Int? let ageGroup: String? let age: Int? let emailAddress: String? let conditioningWorkouts: [String]? let conditioningWorkout: String? let bookings: [String]? let bikeWorkOuts: [String]? let isDeleted: Bool let notes: String? let defaultTB: Double? let defaultOP: Double? let defaultPU: Double? let defaultPB: Double? let defaultBP: Double? let defaultTBReps: Double? let defaultOPReps: Double? let defaultPUReps: Double? let defaultPBReps: Double? let defaultBPReps: Double? let defaultAdvancedPuReps: Double? let defaultAdvancedPu: Double? let defaultPuSeconds: Double? let defaultBroadJumpFeet: Int? let defaultBroadJumpInches: Int? let defaultTwentyFiveYards: Double? let defaultOneFityYards: Double? let status: Int let isActive: Bool let createdBy: String? let lastModifiedBy: String? let lastUpdatedDate: String? let createdDate: String? } // 顶层响应模型 struct FriendsResponse: Codable { let parents: [Parent] let children: [Child] }
2. 修正API服务类,完善Completion Handler和JSON解析
修改API类,补全completion handler类型,并用Alamofire的responseDecodable直接解析数据:
import Alamofire class WebAPILib { let apiURLBase = "https://secreturl.com/api/" func getFriends(completion: @escaping (Result<FriendsResponse, Error>) -> Void) { let endpoint = "Friends/GetAllParentsFriends?parentId=1" guard let url = URL(string: apiURLBase + endpoint) else { completion(.failure(NSError(domain: "Invalid URL", code: -1, userInfo: nil))) return } AF.request(url).responseDecodable(of: FriendsResponse.self) { response in switch response.result { case .success(let data): completion(.success(data)) case .failure(let error): completion(.failure(error)) } } } }
3. 在SwiftUI视图中处理异步数据并展示卡片列表
用@State管理数据状态,确保异步请求返回后更新UI:
struct FriendsView: View { @State private var friendsResponse: FriendsResponse? @State private var isLoading = false @State private var errorMessage: String? private let api = WebAPILib() var body: some View { NavigationStack { VStack { if isLoading { ProgressView("加载中...") } else if let error = errorMessage { Text("出错了:\(error)") .foregroundColor(.red) } else if let response = friendsResponse { List { Section("家长") { ForEach(response.parents) { parent in CardView(title: parent.firstName ?? "未知", subtitle: parent.surname ?? "") } } Section("孩子") { ForEach(response.children) { child in CardView(title: child.fullName ?? "未知", subtitle: child.emailAddress ?? "") } } } } else { Text("点击按钮加载数据") } } .navigationTitle("我的好友") .toolbar { Button("获取好友") { callApi() } } } } private func callApi() { isLoading = true errorMessage = nil api.getFriends { result in DispatchQueue.main.async { isLoading = false switch result { case .success(let response): friendsResponse = response case .failure(let error): errorMessage = error.localizedDescription } } } } } // 自定义卡片视图 struct CardView: View { let title: String let subtitle: String var body: some View { VStack(alignment: .leading, spacing: 4) { Text(title) .font(.headline) Text(subtitle) .font(.subheadline) .foregroundColor(.secondary) } .padding() .background(Color(.systemGray6)) .cornerRadius(8) .padding(.horizontal) } }
内容的提问来源于stack exchange,提问作者dotnetdevcsharp
相关产品推荐
相关产品推荐

