You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 02:33:26