SwiftUI中ObservableObject绑定列表未显示数据求助
SwiftUI List无法展示单词统计结果的解决方法
在实现输入句子统计单词出现次数并通过List展示的功能时,点击Count按钮后数据已正确统计(打印可验证),但List的ForEach循环未生成任何列表项。
问题根源
ListToPrint作为ObservableObject,其内部的wordsToPrint数组未添加@Published属性包装器,导致数组内容变化时无法通知视图刷新。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
相关产品推荐
相关产品推荐

