перезагрузить таблицу с асинхронным результатом поиска - PullRequest
0 голосов
/ 28 августа 2018

Я большое количество данных в моем приложении с функцией поиска. Я использую SQLite и Core Data для поиска и выборки данных.

Вот моя функция поиска,

func fetchSearchResultsWith(_ searchText : String?){

    DispatchQueue.global(qos: .background).async {
        var resArr : [Int64] = []
        let stmt = "SELECT rowid FROM htmlText_fts WHERE htmlText MATCH '\(searchText!)*'"
        do {
            let res = try self.db.run(stmt)
            for row in res {
                resArr.append(row[0] as! Int64)
            }
        } catch {
            print(error.localizedDescription)
        }

        let request : NSFetchRequest<Monos> = Monos.fetchRequest()
        request.fetchLimit = 200
        let predicate = NSPredicate(format: "id in %@", resArr)
        request.predicate = predicate
        var arr : [Items]? = []
        do {
            arr = try context.fetch(request)
        } catch {
            print(error.localizedDescription)
        }

        DispatchQueue.main.async(execute: {
            self.monosSearchResult = arr
            self.tableView.reloadData()
        })
    }
}

Я использую DispatchQueue.global.async , чтобы избежать зависания пользовательского интерфейса, но затем он возвращает асинхронный массив и мое табличное представление перезагружается с неверным результатом. Если я использую DispatchQueue.global.sync , он работает нормально, но мой пользовательский интерфейс зависает при вводе в searchBar. Я не уверен, что я могу сделать, чтобы получить правильный результат. Любая помощь будет оценена!

Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

Ответы [ 2 ]

0 голосов
/ 28 августа 2018

Вы не включили методы источника данных вашей таблицы, которые заполняют таблицу, но я предполагаю, что вы используете значения из self.monosSearchResult. Если нет, то ваш код выборки заполняет неправильные значения, и это может быть частью вашей проблемы.

Кроме того, ваш запрос на выборку должен выполняться в соответствующем потоке для вашего NSManagedObjectContext, а не обязательно (вероятно, нет) глобальной фоновой очереди. NSManagedObjectContext предоставляет методы execute и executeAndWait для правильного использования их очередей.

func fetchSearchResultsWith(_ searchText : String?){

    // context: NSManagedObjectContext, presumably defined in this scope already
    // since you use it below for the fetch.

// CHANGE THIS
// DispatchQueue.global(qos: .background).async {
// TO THIS
    context.perform { // run block asynchronously on the context queue

        var resArr : [Int64] = []
        let stmt = "SELECT rowid FROM htmlText_fts WHERE htmlText MATCH '\(searchText!)*'"
        do {
            let res = try self.db.run(stmt)
            for row in res {
                resArr.append(row[0] as! Int64)
            }
        } catch {
            print(error.localizedDescription)
        }

        let request : NSFetchRequest<Monos> = Monos.fetchRequest()
        request.fetchLimit = 200
        let predicate = NSPredicate(format: "id in %@", resArr)
        request.predicate = predicate
        var arr : [Items]? = []
        do {
            arr = try context.fetch(request)
        } catch {
            print(error.localizedDescription)
        }

        DispatchQueue.main.async(execute: {
            self.monosSearchResult = arr
            self.tableView.reloadData()
        })
    }
}
0 голосов
/ 28 августа 2018

Поскольку у вас есть двухэтапный механизм поиска, новый поиск может быть начат до окончания остальных, поэтому для облегчения этой операции сохраните последнее значение текстового поля внутри переменной

lastSear = textfield.text
fetchSearchResultsWith(lastSear)

затем сделайте это внутри функции поиска в 3 местах

Перед поиском в БД и после и перед настройкой массива и перезагрузкой таблицы

if searchText != lastSear { return }
...