过滤数组时性能迅速降低



我有一个类别类的数组,它有一个名称和父名。我有一个搜索栏,允许用户按类别名称或父名称搜索类别。我的完整数组大约有 600 个项目。键入第一个字母时,大约需要 2-3 秒并冻结键盘上的所有其他输入。在第一个字母之后,一切都很快。

这是我过滤的方式

return self.userData.categories.filter({$0.name.lowercased().hasPrefix(searchText.lowercased()) || ($0.parentName != nil && $0.parentName!.lowercased().hasPrefix(searchText.lowercased()))})

我认为可能是 SwiftUI 渲染所有行,但是初始渲染速度很快。

这就是我渲染类别的方式。

List(categories) { category in
CategoryPickerRowView(category: category, isSelected: category.id == self.transaction.categoryId)
.onTapGesture { self.transaction.categoryId = category.id }
}

更新: 我注意到当键入或删除第一个字母时(当它很慢时(,我在日志中收到此消息

[快照] 对未至少呈现一次的视图(0x7fb6bd4b8080、_UIReplicantView(进行快照需要在 ScreenUpdates:YES。

您可以使用"组合"对搜索进行去抖动,以便仅在用户停止键入后进行。 还可以使用"合并"将筛选器移动到后台,然后将分配移回主队列。

class Model: ObservableObject {
@Published var searchResults: [String] = []
let searchTermSubject = CurrentValueSubject<String, Never>("")
let categorySubject = CurrentValueSubject<String, Never>("")
private var subscriptions = Set<AnyCancellable>()
init() {
Publishers
.CombineLatest(
searchTermSubject
.debounce(for: .milliseconds(250), scheduler: RunLoop.main),
categorySubject
)
.receive(on: DispatchQueue.global(qos: .userInteractive))
.map { combined -> [String] in
// Do search here
}
.receive(on: RunLoop.main)
.assign(to: .searchResults, on: self)
.store(in: &subscriptions)
}
}

通过将.id(UUID())添加到列表中,它可以解决问题。

List(categories) { category in
CategoryPickerRowView(category: category, isSelected: category.id == self.transaction.categoryId)
.onTapGesture { self.transaction.categoryId = category.id }
}.id(UUID())

此处找到的说明:https://www.hackingwithswift.com/articles/210/how-to-fix-slow-list-updates-in-swiftui

使用文本字段委托:-

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
{
if string.isEmpty
{
search = String(search.dropLast())
}else{
search=textField.text!+string
}

并使用".contain"搜索名称。 例如: -

var search:String = ""
var searchData:NSArray?
let filtered = rewardArray?.filter { ($0.name .lowercased()).contains(search.lowercased()) }

searchData = filtered as NSArray?

并使用 searchData 重新加载集合或表

最新更新