Быстрая низкая производительность при фильтрации массива - PullRequest
0 голосов
/ 30 января 2020

У меня есть массив класса 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 ]

1 голос
/ 30 января 2020

Вы можете использовать Объединить, чтобы отменить ваш поиск, так что это происходит только после того, как пользователь перестает печатать. Вы также можете использовать Объединить, чтобы переместить фильтр на задний план, а затем переместить свое назначение обратно в основную очередь.

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)
  }
}
0 голосов
/ 12 февраля 2020

Добавление .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

0 голосов
/ 30 января 2020

Используйте делегат текстового поля: -

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...