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

SwiftUI中使用.searchable从数组动态展示关联数据的问题

SwiftUI .searchable组件搜索关联数据及列表重复问题解决方案

核心问题分析

  1. 数据结构设计不合理:三个独立枚举+全局数组的方式,无法保证名称、编码、价格的对应关系,且全局数组在视图刷新时会被反复填充,导致数据重复。
  2. 视图生命周期错误:在body中直接调用createOtherWound()和removeAll(),而SwiftUI的body会频繁重绘,这会导致数据被反复清空和添加,引发列表重复。
  3. 搜索结果仅返回名称字符串,无法关联对应的编码和价格数据。

解决方案步骤

1. 重构数据模型,整合关联数据

把分散的名称、编码、价格整合到一个结构体中,确保三者一一对应,避免索引匹配错误:

// 整合后的伤口数据模型
struct WoundItem: Identifiable {
    let id = UUID()
    let name: String
    let code: String
    let price: Double
}

// 基于原有枚举生成完整数据数组,保证对应关系
extension WoundItem {
    static let allItems: [WoundItem] = [
        WoundItem(name: OtherWoundsName.secondaryclosure_name.rawValue, code: OtherWoundsCode.secondaryclosure_code.rawValue, price: OtherWoundsValue.secondaryclosure_value.rawValue),
        WoundItem(name: OtherWoundsName.musclerepair_name.rawValue, code: OtherWoundsCode.musclerepair_code.rawValue, price: OtherWoundsValue.musclerepair_value.rawValue),
        WoundItem(name: OtherWoundsName.woundone_name.rawValue, code: OtherWoundsCode.woundone_code.rawValue, price: OtherWoundsValue.woundone_value.rawValue),
        WoundItem(name: OtherWoundsName.woundtwo_name.rawValue, code: OtherWoundsCode.woundtwo_code.rawValue, price: OtherWoundsValue.woundtwo_value.rawValue),
        WoundItem(name: OtherWoundsName.woundthree_name.rawValue, code: OtherWoundsCode.woundthree_code.rawValue, price: OtherWoundsValue.woundthree_value.rawValue),
        WoundItem(name: OtherWoundsName.woundfourmore_name.rawValue, code: OtherWoundsCode.woundfourmore_code.rawValue, price: OtherWoundsValue.woundfourmore_value.rawValue),
        WoundItem(name: OtherWoundsName.debrideone_name.rawValue, code: OtherWoundsCode.debrideone_code.rawValue, price: OtherWoundsValue.debrideone_value.rawValue),
        WoundItem(name: OtherWoundsName.debridetwo_name.rawValue, code: OtherWoundsCode.debridetwo_code.rawValue, price: OtherWoundsValue.debridetwo_value.rawValue),
        WoundItem(name: OtherWoundsName.extensortendon_name.rawValue, code: OtherWoundsCode.extensortendon_code.rawValue, price: OtherWoundsValue.extensortendon_value.rawValue),
        WoundItem(name: OtherWoundsName.flexortendor_name.rawValue, code: OtherWoundsCode.flexortendor_code.rawValue, price: OtherWoundsValue.flexortendor_value.rawValue),
        WoundItem(name: OtherWoundsName.fbskin_name.rawValue, code: OtherWoundsCode.fbskin_code.rawValue, price: OtherWoundsValue.fbskin_value.rawValue),
        WoundItem(name: OtherWoundsName.fbskinsedation_name.rawValue, code: OtherWoundsCode.fbskinsedation_code.rawValue, price: OtherWoundsValue.fbskinsedation_value.rawValue),
        WoundItem(name: OtherWoundsName.fbdermissedation_name.rawValue, code: OtherWoundsCode.fbdermissedation_code.rawValue, price: OtherWoundsValue.fbdermissedation_value.rawValue),
        WoundItem(name: OtherWoundsName.flapface5_name.rawValue, code: OtherWoundsCode.flapface5_code.rawValue, price: OtherWoundsValue.flapface5_value.rawValue),
        WoundItem(name: OtherWoundsName.flapother5_name.rawValue, code: OtherWoundsCode.flapother5_code.rawValue, price: OtherWoundsValue.flapother5_value.rawValue),
        WoundItem(name: OtherWoundsName.flapface5plus_name.rawValue, code: OtherWoundsCode.flapface5plus_code.rawValue, price: OtherWoundsValue.flapface5plus_value.rawValue),
        WoundItem(name: OtherWoundsName.flapother5plus_name.rawValue, code: OtherWoundsCode.flapother5plus_code.rawValue, price: OtherWoundsValue.flapother5plus_value.rawValue),
        WoundItem(name: OtherWoundsName.fingerdebride_name.rawValue, code: OtherWoundsCode.fingerdebride_code.rawValue, price: OtherWoundsValue.fingerdebride_value.rawValue),
        WoundItem(name: OtherWoundsName.handdebride_name.rawValue, code: OtherWoundsCode.handdebride_code.rawValue, price: OtherWoundsValue.handdebride_value.rawValue),
        WoundItem(name: OtherWoundsName.facedebride_name.rawValue, code: OtherWoundsCode.facedebride_code.rawValue, price: OtherWoundsValue.facedebride_value.rawValue),
        WoundItem(name: OtherWoundsName.otherdebride_name.rawValue, code: OtherWoundsCode.otherdebride_code.rawValue, price: OtherWoundsValue.otherdebride_value.rawValue),
        WoundItem(name: OtherWoundsName.ampulatephalanx_name.rawValue, code: OtherWoundsCode.ampulatephalanx_code.rawValue, price: OtherWoundsValue.ampulatephalanx_value.rawValue),
        WoundItem(name: OtherWoundsName.revisionfingertip_name.rawValue, code: OtherWoundsCode.revisionfingertip_code.rawValue, price: OtherWoundsValue.revisionfingertip_value.rawValue)
    ]
}

// 保留原有枚举(如果不需要可删除,这里用于生成数据)
enum OtherWoundsName: String, CaseIterable {
    case secondaryclosure_name = "Secondary Closure"
    case musclerepair_name = "Muscle Repair (including skin)"
    case woundone_name = "Debride Wound/Ulcer - One"
    case woundtwo_name = "Debride Wound/Ulcer - Two"
    case woundthree_name = "Debride Wound/Ulcer - Three"
    case woundfourmore_name = "Debride Wound/Ulcer - Four Plus"
    case debrideone_name = "Debride into Tendon/Bone/Bursa/Bone"
    case debridetwo_name = "Debride into Tendon/Bone/Bursa/Bone - Two or More"
    case extensortendon_name = "Extensor Tendon Repair"
    case flexortendor_name = "Flexor Tendon Repair"
    case fbskin_name = "FB Skin"
    case fbskinsedation_name = "FB Skin with Sedation"
    case fbdermissedation_name = "FB Dermis with Sedation"
    case flapface5_name = "Advancement Flap: Neck Up < 5.1cm"
    case flapother5_name = "Advancement Flap: Other < 5.1cm"
    case flapface5plus_name = "Advancement Flap: Neck up > 10.1cm"
    case flapother5plus_name = "Advancement Flap: Other > 10.1.cm"
    case fingerdebride_name = "Finger Debridement"
    case handdebride_name = "Hand Debridement"
    case facedebride_name = "Face Debridement"
    case otherdebride_name = "Other per % BSA"
    case ampulatephalanx_name = "Amputate Phalanx"
    case revisionfingertip_name = "Revision of Amputation Finger Tip"
}
enum OtherWoundsCode: String, CaseIterable {
    case secondaryclosure_code = "Z738"
    case musclerepair_code = "R525"
    case woundone_code = "Z080"
    case woundtwo_code = "Z081"
    case woundthree_code = "Z082"
    case woundfourmore_code = "Z083"
    case debrideone_code = "Z084"
    case debridetwo_code = "Z085"
    case extensortendon_code = "R578"
    case flexortendor_code = "R585"
    case fbskin_code = "Z114"
    case fbskinsedation_code = "Z115"
    case fbdermissedation_code = "R517"
    case flapface5_code = "R011"
    case flapother5_code = "R002"
    case flapface5plus_code = "R012"
    case flapother5plus_code = "R003"
    case fingerdebride_code = "R660"
    case handdebride_code = "R661"
    case facedebride_code = "R662"
    case otherdebride_code = "R637"
    case ampulatephalanx_code = "R606"
    case revisionfingertip_code = "R629"
}
enum OtherWoundsValue: Double, CaseIterable {
    case secondaryclosure_value = 97.35
    case musclerepair_value = 88.60
    case woundone_value = 20
    case woundtwo_value = 30
    case woundthree_value = 45
    case woundfourmore_value = 60
    case debrideone_value = 60.001
    case debridetwo_value = 90
    case extensortendon_value = 164.10
    case flexortendor_value = 307.60
    case fbskin_value = 25.20
    case fbskinsedation_value = 88.80
    case fbdermissedation_value = 107.70
    case flapface5_value = 89.85
    case flapother5_value = 67.40
    case flapface5plus_value = 247.15
    case flapother5plus_value = 161.75
    case fingerdebride_value = 28.90
    case handdebride_value = 47.85
    case facedebride_value = 28.901
    case otherdebride_value = 29.68
    case ampulatephalanx_value = 161.45
    case revisionfingertip_value = 241.55
}

2. 重构ContentView,修复视图生命周期和搜索逻辑

移除全局数组,改用本地状态管理,直接使用预定义的静态数组,并基于整合后的模型实现搜索:

struct ContentView: View {
    @State private var searchText = ""
    
    // 直接使用预定义的完整伤口数据数组
    private let allWounds = WoundItem.allItems
    
    var body: some View {
        NavigationView {
            List(searchResults) { item in
                VStack(alignment: .leading, spacing: 8) {
                    Text(item.name)
                        .font(.caption)
                    HStack {
                        Text("Code: \(item.code)")
                            .font(.caption)
                        Spacer()
                        Text(String(format: "$%.2f", item.price))
                            .font(.caption)
                    }
                }
                .padding()
                .border(Color.gray)
            }
            .searchable(text: $searchText, prompt: "Search wounds...")
        }
    }
    
    // 基于整合模型的搜索结果计算属性
    var searchResults: [WoundItem] {
        if searchText.isEmpty {
            return [] // 搜索为空时不展示数据,需展示全部可替换为allWounds
        } else {
            return allWounds.filter { $0.name.localizedCaseInsensitiveContains(searchText) }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

3. 关键优化点说明

  • 数据结构整合:用WoundItem结构体绑定名称、编码、价格,彻底解决三者关联问题,ForEach中可直接获取所有字段。
  • 避免重复加载:移除全局数组和createOtherWound()方法,改用静态预定义的allItems数组,不会因视图重绘反复填充数据。
  • 搜索逻辑优化:搜索结果返回完整的WoundItem对象,而非单独的名称字符串,直接支持展示所有关联数据。
  • 视图生命周期修正:不在body中执行数据修改操作,避免因SwiftUI自动重绘导致的数据异常。

可选优化

如果需要保留原有枚举的动态生成逻辑(比如枚举可能扩展),可以替换WoundItem.allItems的生成方式,通过枚举的case索引匹配:

static let allItems: [WoundItem] = zip(zip(OtherWoundsName.allCases, OtherWoundsCode.allCases), OtherWoundsValue.allCases).map {
    WoundItem(name: $0.0.0.rawValue, code: $0.0.1.rawValue, price: $0.1.rawValue)
}

注意:这种方式要求三个枚举的case数量和顺序完全一致,否则会出现对应错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 00:15:37