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

iOS端REST API请求Firestore时引用数组的Codable解码问题

解码Firestore REST API返回的引用类型数组方案

你解码失败的核心原因是没有匹配listaRefsLinea的多层嵌套结构:这个字段外层是arrayValue包装,内部values数组的每个元素又被referenceValue包装,和普通字符串字段的单层stringValue结构不一样,按层级逐次解码即可,不需要依赖Firebase SDK。

第一步:补充对应字段结构的Codable包装类型

先加两个辅助结构体,匹配Firestore返回的数组、引用类型包装格式:

// 匹配Firestore数组字段的外层包装
struct ArrayValue: Codable {
    let values: [ReferenceValue]
}

// 匹配Firestore文档引用字段的包装
struct ReferenceValue: Codable {
    let refPath: String
    
    private enum CodingKeys: String, CodingKey {
        case refPath = "referenceValue"
    }
}

第二步:替换原有占位的listaRefsLinea解码逻辑

把你代码里listaRefsLinea = [""]这行替换成下面的代码,逐层解包:

// 先解出arrayValue层
let arrayWrapper = try fieldContainer.decode(ArrayValue.self, forKey: .listaRefsLinea)
// 遍历数组元素,提取每个referenceValue里的路径字符串
listaRefsLinea = arrayWrapper.values.map(\.refPath)

注意:你原来BrandKeys枚举里多写了一个listaRefsLinea的case,这个字段是在fields嵌套容器里的,外层容器不存在这个键,记得删掉,否则解码其他字段时可能出错。

修正后的完整解码代码

import Foundation

struct BrandResponse : Codable {
    let brands : [Brand_Struct]
    
    private enum CodingKeys : String, CodingKey {
        case brands = "documents"
    }
}

struct StringValue : Codable {
    let value : String
    
    private enum CodingKeys : String, CodingKey {
        case value = "stringValue"
    }
}

struct ArrayValue: Codable {
    let values: [ReferenceValue]
}

struct ReferenceValue: Codable {
    let refPath: String
    
    private enum CodingKeys: String, CodingKey {
        case refPath = "referenceValue"
    }
}

struct Brand_Struct : Codable {
    let url_logo : String
    let web_url : String
    let nome_brand : String
    let descrizione : String
    let listaRefsLinea : [String]
    let descrizione_en : String
    let data_consumption : String
    
    private enum BrandKeys : String, CodingKey {
        case fields
    }
    
    private enum FieldKeys : String, CodingKey {
        case url_logo
        case web_url
        case nome_brand
        case descrizione
        case listaRefsLinea
        case descrizione_en
        case data_consumption
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: BrandKeys.self)
        let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields)
        
        nome_brand = try fieldContainer.decode(StringValue.self, forKey: .nome_brand).value
        web_url = try fieldContainer.decode(StringValue.self, forKey: .web_url).value
        url_logo = try fieldContainer.decode(StringValue.self, forKey: .url_logo).value
        descrizione = try fieldContainer.decode(StringValue.self, forKey: .descrizione).value
        descrizione_en = try fieldContainer.decode(StringValue.self, forKey: .descrizione_en).value
        data_consumption = try fieldContainer.decode(StringValue.self, forKey: .data_consumption).value
        
        let arrayWrapper = try fieldContainer.decode(ArrayValue.self, forKey: .listaRefsLinea)
        listaRefsLinea = arrayWrapper.values.map(\.refPath)
    }
}

扩展说明

Firestore REST API返回的所有字段都遵循{类型标识: 实际值}的固定包装格式:

  • 字符串:{"stringValue": "内容"}
  • 数字:{"integerValue"/"doubleValue": "数值"}
  • 布尔值:{"booleanValue": true/false}
  • 时间戳:{"timestampValue": "时间字符串"}
  • 数组:{"arrayValue": {"values": [子元素]}}
  • 引用:{"referenceValue": "文档全路径"}
    后续如果需要解码其他类型字段,只需要按照对应结构新增对应的包装结构体即可,不需要引入额外SDK。
    解码后拿到的listaRefsLinea元素是文档全路径,如果只需要末尾的文档ID,直接对字符串做split(separator: "/").last截取就行。

内容的提问来源于stack exchange,提问作者MatBuompy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:27:26