SwiftUI实现多选项选择并转为特征对象数组的问题
处理特征多选结果存储与回传格式问题
问题背景
从API获取的响应结构:
"features": [ { "name": "Safety", "_id": "636a638959d10a2603b8d645", "values": [ "Array of String" ] }, { "name": "Entertainment", "_id": "636a64312bbe0cd292a1ffc6", "values": [ "Array of String" ] } ]
使用以下结构体解码:
struct Feature : Codable , Hashable{ var name : String = "" var values : [Value] = [] } struct Value : Codable, Hashable{ var value : String = "" var unit : String = "" }
视图渲染逻辑中,用户可从每个特征的选项列表中多选,需要将选中结果存储并生成指定格式的回传JSON:
{ "features": [ { "Safety": [ "value1", "value9", "value3" ] }, { "Entertainment": [ "value7", "value2", "value8" ] } ] }
解决方案
1. 设计选中状态存储结构
用字典存储每个特征对应的选中值列表,键用特征的name(若存在重名风险,建议用_id更可靠),值为选中的value字符串数组:
@State private var selectedFeatures: [String: [String]] = [:]
2. 绑定选中状态与更新逻辑
修改视图中FeatureCell的选中判断和点击事件,实现选中/取消的逻辑:
ForEach(Array(features.enumerated()), id: \.offset) { featureIndex, feature in HStack{ Text(feature.name).font(Font.body.bold()) Spacer() }.padding(.bottom , 10) ScrollView(.horizontal, showsIndicators: false){ HStack(spacing : 10){ ForEach(Array(feature.values.enumerated()), id: \.offset) { valueIndex, value in // 判断当前值是否已选中 let isSelected = selectedFeatures[feature.name]?.contains(value.value) ?? false FeatureCell(isSelected: .constant(isSelected), value: value) .onTapGesture { // 更新选中列表 if var selectedValues = selectedFeatures[feature.name] { if isSelected { // 取消选中:移除对应值 selectedValues.removeAll { $0 == value.value } } else { // 选中:添加对应值 selectedValues.append(value.value) } selectedFeatures[feature.name] = selectedValues } else { // 首次选中:初始化数组 selectedFeatures[feature.name] = [value.value] } } } } Divider().padding(10) } }.padding(15)
3. 生成指定格式的回传JSON
将字典转换为要求的数组格式,再编码为JSON:
// 转换为目标格式:每个元素是单个键值对的字典 let outputFeatures = selectedFeatures.map { [ $0.key: $0.value ] } let outputDictionary = ["features": outputFeatures] // 编码为JSON数据 do { let jsonData = try JSONSerialization.data(withJSONObject: outputDictionary, options: .prettyPrinted) if let jsonString = String(data: jsonData, encoding: .utf8) { // 此处可将jsonString发送至API print(jsonString) } } catch { print("JSON编码错误:\(error)") }
优化建议
如果特征存在重名情况,建议用_id作为字典的键,生成JSON时再替换为name,避免冲突:
// 存储时用_id @State private var selectedFeatures: [String: [String]] = [:] // 生成JSON时转换 let outputFeatures = selectedFeatures.compactMap { featureId, selectedValues in guard let feature = features.first(where: { $0._id == featureId }) else { return nil } return [feature.name: selectedValues] }
内容的提问来源于stack exchange,提问作者Mohammed Riyadh
相关产品推荐
相关产品推荐

