过滤数组时性能迅速下降

时间:2020-01-30 05:47:21

标签: swift swiftui

我有一个Category类的数组,该类具有名称和parentName。我有一个搜索栏,允许用户通过类别名称或parentName搜索类别。我的全套产品大约有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)需要afterScreenUpdates:YES。

3 个答案:

答案 0 :(得分:1)

您可以使用“合并”对搜索进行反跳操作,以便仅在用户停止键入后才进行搜索。您还可以使用合并将过滤器移至后台,然后将分配移回主队列。

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)
  }
}

答案 1 :(得分:1)

通过将.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

答案 2 :(得分:-1)

使用文本字段委托:-

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重新加载您的集合或表