fetchBatchSize и кеш в NSFetchedResultsController игнорируются - PullRequest
0 голосов
/ 02 июня 2018

Я использую NSFetchedResultsController для отображения сообщений в приложении чата.

Переменная контекста назначается в appDelegate, а ссылка на этот контекст используется в чате.

let context = persistentContainer.viewContext

Я инициализирую NSFRC следующим образом в viewDidLoad:

func initializeResultsController() {
    let request = NSFetchRequest<Message>(entityName: "Message")
    let messageSort = NSSortDescriptor(key: "dateCreated", ascending: true)

    request.sortDescriptors = [messageSort]
    request.predicate = NSPredicate(format: "chatRoomId == %@", self.chatRoomId)
    request.fetchBatchSize = 30

    fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: "messageDateSectionIdentifier", cacheName: self.chatRoomId)
    fetchedResultsController.delegate = self

    do {
        try fetchedResultsController.performFetch()
    } catch {
        fatalError("Failed to initialize FetchedResultsController: \(error)")
    }
}

SectionNameKeyPath ("messageDateSectionIdentifier") является производным свойством, так что разделы могут быть разделены на календарные дни.

У меня есть двапроблемы.Во-первых, кажется, что batchSize игнорируется, а во-вторых, кэш, похоже, не влияет на производительность.Чем больше сообщений, тем дольше задержка при выборе комнаты чата.примерно 1 секунда для 1500 сообщений.

Когда я редактирую схему для отображения информации coreData в консоли, пакетный запрос для 30 строк выполняется несколько раз, когда впервые появляется представление, и в одном случае размер массива равен 1500. Неубедитесь, что это массив ошибок или заполненный массив.PrintOut консоли:

CoreData: annotation: sql connection fetch time: 0.0013s
CoreData: annotation: total fetch execution time: 0.0014s for 1454 rows.
CoreData: annotation: Bound intarray _Z_intarray0
CoreData: annotation: Bound intarray values.

И это повторяется после этого несколько раз со значением 30 строк.

Я попытался упростить sectionNameKeyPath до dateCreated, чтобы увидеть, были ли производные разделыпроблема, но не было никакой разницы вообще.Я должен также упомянуть, что, как и во всех чат-приложениях, приложение изначально прокручивается до самого дна при его представлении.

Я хочу, чтобы кеш работал, а также чтобы fetchBatchSize работал так, чтобы только 30 строкизначально выбираются из coreData до тех пор, пока пользователь не начнет прокручиваться вверх.Задержка, вызванная этим методом, оказывает ощутимое влияние на производительность моего приложения.

Ответы [ 2 ]

0 голосов
/ 08 июля 2018

Я наконец нашел причину проблемы в моем случае.

Если вы ссылаетесь на fetchedResultsController в tableView heightForRowAt, то fetchBatchSize будет циклически проходить и загружать все данные в циклах указанного вами fetchBatchSize.

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let item = self.fetchedResultsController!.object(at: indexPath)

    // get and return height of item
    return item.heightOfItem
}

Если вы используете UITableViewAutomaticDimension или определяете высоту, для которой не требуется ссылка на fetchedResultsController (то есть с фиксированной высотой), тогда у вас не возникнет этой проблемы, и fetchBatchSize будет работать так, как должно.

К сожалению, я обнаружил, что UITableViewAutomaticDimension неприемлемо для производительности прокрутки, поэтому я думаю, что мне нужно вручную настраивать пакетную загрузку, используя смещения.

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

Если у вас проблемы с fetchBatchSize с NSFetchedResultsController, я бы посоветовал рассмотреть эти две проблемы.

0 голосов
/ 03 июня 2018

Вы правы, что batchSize не соблюдается fetchedResultsController.NSFetchedResultsController делает выборку и затем отслеживает все изменения в контексте, чтобы видеть, добавлено ли что-либо, удалено, перемещено или изменено.Если бы он выбрал только подмножество соответствующих объектов, соблюдая batchSize, он не смог бы выполнить свою работу.

Вы можете обойти это, установив предикат, который будет получать сообщения только после определенной даты.Чтобы выяснить, какова дата отсечения, вы можете сначала сделать одну выборку, где batchSize = 1 и batchOffset = [сколько сообщений вы хотите изначально в fetchedResultsController].Чем больше сообщений поступит в коллекцию, тем больше будет размер, превышающий ваш начальный лимит.

Также имейте в виду, что sectionNameKeyPath вызывается для КАЖДОГО элемента в коллекции.Таким образом, выполнение даже небольшого объема работы может привести к огромным задержкам.Не создавайте календарь или dataFormatter в тогда sectionNameKeyPath - используйте повторно один.

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