SwiftUI ForEach用ObservedObject过滤FetchedResults无更新问题求助
问题原因及解决方案
问题判定
这不是ObservedObject相关的问题:
- 你在MasterView中可以正常渲染
Text(String(textItem.text)),说明RecognizedContent的@Published属性变更已经正常触发了视图刷新 - 进入详情页后
Text(text)可以正常展示内容,说明字符串已经正确传递到TextPreviewView,传值链路没有问题
核心问题根源
两个常见原因:
- 传入的
text存在肉眼不可见的冗余字符:比如OCR/输入生成的内容带了首尾空格、换行符、零宽空格,渲染成Text时不会显示,但是字符串匹配时会导致判定不匹配 - 直接在
ForEach中对FetchedResults做实时过滤:FetchedResults是懒加载类型,部分iOS版本下直接在body的计算属性中做过滤,可能出现过滤逻辑触发时机异常,你把值赋值给@State后会强制触发视图重绘,过滤逻辑重新执行就可以正常返回结果
解决方案
第一步:先确认字符串实际内容
在TextPreviewView的body中添加调试代码,确认传入的text和目标值是否完全一致:
// 加在VStack之前即可 let _ = print("传入文本:<\(text)>,长度:\(text.count)") let _ = print("目标文本:<Benjamin>,长度:\("Benjamin".count)")
如果两个长度不一致,说明存在多余字符。
第二步:文本预处理+优化过滤逻辑
对传入的text做去首尾空白处理后再过滤,同时建议把过滤逻辑从ForEach移到@FetchRequest的谓语中,性能更高也更稳定:
struct TextPreviewView: View { var text: String @Environment(\.managedObjectContext) private var viewContext @FetchRequest private var plants: FetchedResults<Plant> // 自定义初始化方法设置动态过滤谓语 init(text: String) { self.text = text // 预处理文本:去掉首尾空白和换行 let processedText = text.trimmingCharacters(in: .whitespacesAndNewlines) // [c]表示不区分大小写,CONTAINS表示包含匹配 let predicate = NSPredicate(format: "wrappedID CONTAINS[c] %@", processedText) _plants = FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \Plant.timestamp, ascending: true)], predicate: predicate, animation: .default ) } var body: some View { VStack { Text(text) .font(.body) .padding() // 不需要再手动过滤,直接遍历FetchRequest返回的结果即可 ForEach(plants, id: \.self) { plant in PlantRow(item: plant) Text(plant.visualId ?? "") } } } }
内容的提问来源于stack exchange,提问作者FrontFacingWindowCleaner
相关产品推荐
相关产品推荐

