Xcode(Swift)中使用Alamofire提取API返回JSON的指定对象
问题根因
你当前无法提取指定分类字段,核心是3个代码逻辑错误:
- 数据模型和接口返回结构完全不匹配:接口根节点是数组,不是你定义的带
Datos字段的对象;返回的分类是categorie1到categorie66个独立字段,不是单个categorie字符串属性 - 网络层逻辑错误:虽然调用了
responseDecodable,但实际没有使用解析后的结构体,直接把原始二进制数据转成JSON字符串返回,完全没做结构化解析 - 方法命名和功能不匹配:当前写的
getUsers方法实际是请求分类数据,冗余的user、pass参数完全没有用到
修正实现
1. 重写数据模型,匹配真实JSON结构
替换ResponseWS文件内的原有代码,直接对齐接口返回结构:
import Foundation struct CategoryItem: Decodable { let id: String let categorie1: String let categorie2: String let categorie3: String let categorie4: String let categorie5: String let categorie6: String // 可选:计算属性直接返回所有分类的数组,方便列表展示 var allCategories: [String] { [categorie1, categorie2, categorie3, categorie4, categorie5, categorie6] } }
2. 重构网络请求层,正确解析结构化数据
替换ConnectWS文件内的原有代码,去掉冗余参数,回调直接返回解析完成的模型:
import Foundation import Alamofire class ConnectWS{ static let shared = ConnectWS() private let urlBase = "https://62858a2ff0e8f0bb7c057f14.mockapi.io/categorias" private let validStatus = 200...299 func fetchCategories(success: @escaping(_ categories: [CategoryItem]) -> (), failure: @escaping(_ error: Error) -> ()) { AF.request(urlBase, method: .get) .validate(statusCode: validStatus) .responseDecodable(of: [CategoryItem].self) { response in switch response.result { case .success(let list): success(list) case .failure(let err): failure(err) } } } }
3. 修改页面调用逻辑,按需提取指定字段
替换ViewController内的按钮点击逻辑,直接从解析好的模型里取需要的字段即可:
import UIKit class ViewControllerCategorias: UIViewController { @IBOutlet weak var name: UILabel! @IBOutlet weak var message: UILabel! @IBOutlet weak var buttonOutlet: UIButton! override func viewDidLoad() { super.viewDidLoad() } @IBAction func buttonAction(_ sender: Any) { ConnectWS.shared.fetchCategories(success: { list in guard let firstItem = list.first else { self.message.text = "暂无分类数据" return } // 按需提取指定字段即可,示例: // 取第一个分类Fruits展示 self.name.text = firstItem.categorie1 // 如果要展示所有分类,直接拼接数组即可 // self.name.text = firstItem.allCategories.joined(separator: "、") // 如果要取第三个分类Juices,直接取firstItem.categorie3即可 }, failure: { err in self.message.text = err.localizedDescription }) } }
扩展:动态提取任意序号的分类
如果你后续需要按序号动态取分类、不想硬编码6个分类属性,可以给模型加自定义解码逻辑,支持按下标取值:
struct CategoryItem: Decodable { let id: String private let categoryStore: [String: String] init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: GenericCodingKey.self) id = try container.decode(String.self, forKey: GenericCodingKey(stringValue: "id")!) var store = [String: String]() for key in container.allKeys { if key.stringValue.hasPrefix("categorie"), let value = try? container.decode(String.self, forKey: key) { store[key.stringValue] = value } } categoryStore = store } // 传入分类序号,返回对应分类名,比如传入3返回"Juices" func getCategory(no: Int) -> String? { categoryStore["categorie\(no)"] } } // 通用CodingKey,用于遍历动态字段 struct GenericCodingKey: CodingKey { var stringValue: String init?(stringValue: String) { self.stringValue = stringValue } var intValue: Int? init?(intValue: Int) { self.stringValue = "\(intValue)" self.intValue = intValue } }
调用时直接用firstItem.getCategory(no: 2)就能拿到第二个分类Animals,不需要硬编码属性。
内容的提问来源于stack exchange,提问作者emiliorivas16
相关产品推荐
相关产品推荐

