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

SwiftUI点击列表Checkbox生成指定结构JSON数组的实现问题

问题核心原因

你当前的实现存在4个关键逻辑错误:

  • 存储逻辑错误:AddNurseryCard是列表的单个子项视图,你把全局的nurseryData数组存在单个子项中,每个子项的数组是独立的,根本无法累加所有选中项的数据
  • 取值key错误:你定义的data字典里数组对应的key是nurseryData,但取值时写的是data["nurseryCode"],永远拿不到正确的数组,只能得到空值
  • 接口参数结构错误:你当前直接把单个选中项的参数传给接口,没有拼接成要求的{"nurseryData": [选中项1, 选中项2...]}结构
  • 缺少取消选中的处理逻辑:只处理了选中的情况,用户取消勾选时没有对应删除数组里的项
正确实现思路
  1. 把选中项的数组放在列表的父视图中统一管理,用@State修饰保证状态变化时刷新视图
  2. 子项AddNurseryCard通过回调闭包,把当前项的选中状态、对应ssoId和nurseryCode传递给父视图
  3. 父视图收到回调后,根据选中状态,往全局数组里添加/删除对应项,得到的数组天然就是你需要的结构
  4. 提交接口时直接把全局数组包装成要求的字典结构即可
修改后的代码示例

列表父视图示例

// 承载列表的父视图,你需要替换成你自己的列表页面代码
struct NurseryListView: View {
    // 全局存储所有选中的项,结构完全符合你要的nurseryData要求
    @State private var selectedNurseryData: [[String: String]] = []
    // 你的列表数据源,替换成你实际的数据源
    let nurseryList: [AddNurseryModels.Data] = []
    
    var body: some View {
        List(nurseryList, id: \.nurseryCode) { model in
            AddNurseryCard(models: model) { isSelected, ssoId, nurseryCode in
                if isSelected {
                    // 选中时添加到数组
                    selectedNurseryData.append(["SSOId": ssoId, "nurseryCode": nurseryCode])
                } else {
                    // 取消选中时从数组删除对应项
                    selectedNurseryData.removeAll { $0["nurseryCode"] == nurseryCode }
                }
                
                // 如果需要每次选中就提交接口,在这里组装参数即可
                let params: [String: Any] = [
                    "nurseryData": selectedNurseryData
                ]
                print(params) // 这里输出的就是你要求的JSON结构,直接传给接口即可
                // addNursery(params: params)
            }
        }
    }
    
    // 接口请求方法放到父视图更合理
    func addNursery(params :[String:Any]) {
        let url = Constants.init().devUrl + Api.init().addNursery
        let headers : HTTPHeaders = HTTPHeaders(["ApiKey" : Constants.init().apiKey])
        AF.request(url,method: .post,parameters: params, encoding:JSONEncoding.default, headers: headers).responseJSON { response in
            switch response.result{
            case .failure(let error):
                print(error)
            case .success(let json):
                print(json)
            }
        }
    }
}

改造后的AddNurseryCard子项代码

import SwiftUI

struct AddNurseryCard: View {
    @State private var checked = false
    let models : AddNurseryModels.Data
    // 选中状态变化的回调,传出是否选中、ssoId、苗圃编码
    var onCheckChanged: (Bool, String, String) -> Void
 
    var body: some View {
        HStack{
            Image("nursery")
            Divider()
            VStack(alignment: .leading) {
                if (models.isUrban ?? 0) != 0 {
                    Text((models.nurseryName ?? "") + " (U)")
                } else {
                    Text((models.nurseryName ?? "") + " (R)")
                }
                Text(models.rANGE_NAME ?? "")
                if (models.isActiveForGGAY ?? 0) != 0 {
                    Text("Is Active For GGAY : Yes")
                } else {
                    Text("Is Active For GGAY : NO")
                }
            }
           
            CheckBoxView(checked: $checked)
                .onAppear() {
                    checked = (models.isActiveForGGAY ?? 0) != 0
                }
                .onChange(of: checked, perform: { value in
                    // 读取ssoId,建议这部分逻辑可以放到父视图,不用每个子项都重复读取
                    let result = UserDefaults.standard.value(forKey: "profile")
                    let profile = ProfileModels(dict: result as? [String : Any] ?? [:])
                    let ssoId = (profile.data?.first?.ssoid ?? "") as String
                    let nurseryCode = models.nurseryCode ?? ""
                    // 把状态传给父视图处理
                    onCheckChanged(value, ssoId, nurseryCode)
                })
        }
        Divider()
    }
}
额外优化建议
  • 可选值不要强行解包,用??给默认值,避免闪退
  • UserDefaults读用户信息的逻辑建议只在父视图读一次,不用每个子Cell都重复读,性能更好
  • 如果你的列表数据量大,建议用结构体代替[String: String]存储选中项,后续维护更方便

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 01:54:03