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

SwiftUI中ObservableObject绑定列表未显示数据求助

SwiftUI List无法展示单词统计结果的解决方法

在实现输入句子统计单词出现次数并通过List展示的功能时,点击Count按钮后数据已正确统计(打印可验证),但List的ForEach循环未生成任何列表项。

问题根源

  1. ListToPrint作为ObservableObject,其内部的wordsToPrint数组未添加@Published属性包装器,导致数组内容变化时无法通知视图刷新。
  2. Word是引用类型(类),修改已有实例的nTimes属性时,数组元素的引用未发生变化,无法触发视图更新。

修复方案

1. 为ObservableObject的数组添加@Published修饰

修改ListToPrint类,让数组变化能自动通知视图:

class ListToPrint: ObservableObject {
    @Published var wordsToPrint: [Word] = []
    // 其余代码保持不变
}

2. 将Word改为值类型(struct)

结构体是值类型,修改属性时会触发数组元素的变化,配合@Published可让视图感知更新:

struct Word: Identifiable {
    var id: String
    var nTimes: Int = 1
    
    init(string: String) {
        self.id = string
    }
    
    mutating func count() { self.nTimes += 1 }
}

注意:结构体中修改属性的方法需要添加mutating关键字。

3. 优化update方法的查找逻辑

减少重复调用first(where:),提升性能:

func update(sentence: String){
    let componentsOfSentence = getStrComponentsArray(str: sentence)
    
    for comp in componentsOfSentence {
        if let index = wordsToPrint.firstIndex(where: {$0.id == comp}) {
            wordsToPrint[index].count()
        } else {
            wordsToPrint.append(Word(string: comp))
        }
    }
}

完整修改后的代码

import SwiftUI
import Foundation

struct Word: Identifiable {
    var id: String
    var nTimes: Int = 1
    
    init(string: String) {
        self.id = string
    }
    
    mutating func count() { self.nTimes += 1 }
}

class ListToPrint: ObservableObject {
    @Published var wordsToPrint: [Word] = []
    
    init() {}
    
    init(sentence: String){
        self.update(sentence: sentence)
    }
    
    func update(sentence: String){
        let componentsOfSentence = getStrComponentsArray(str: sentence)
        
        for comp in componentsOfSentence {
            if let index = wordsToPrint.firstIndex(where: {$0.id == comp}) {
                wordsToPrint[index].count()
            } else {
                wordsToPrint.append(Word(string: comp))
            }
        }
    }
        
    func getStrComponentsArray(str: String) -> [String] {
        return str.components(separatedBy: " ")
    }
}

struct ContentView: View {
    @State private var sentence = ""
    @ObservedObject private var listOfWordsCounted = ListToPrint()
        
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
            Text("Hello, world!")
            
            TextField("Let me count your sentence", text: $sentence)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            
            Button("Count") {
                listOfWordsCounted.update(sentence: sentence)
                print(listOfWordsCounted.wordsToPrint)
            }
            .foregroundColor(.red)
            .padding()
            .background(Color(red: 0, green: 0, blue: 0.5))
            .clipShape(Capsule())

            Button("Print") {
                listOfWordsCounted.wordsToPrint.forEach { print($0.id) }
            }

            List {
                ForEach(listOfWordsCounted.wordsToPrint) { word in
                    HStack {
                        Text(word.id)
                        Spacer()
                        Text("\(word.nTimes) times")
                    }
                }
            }
        }
        .padding()
    }
}

内容的提问来源于stack exchange,提问作者Gonçalo Lourenço

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 10:35:11