NSFetchedResultsController sectionNameKeyPath不尊重fetchBatchSize

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NSFetchedResultsController sectionNameKeyPath不尊重fetchBatchSize相关的知识,希望对你有一定的参考价值。

对不起核心数据noob在这里......

我在NSFetchedResultsController上使用UITableViewController。实体中的数据包含timestamps。作为sectionID我想在节标题中使用日期。但是当我使用sectionNameKeyPath时,Core Data加载所有数据而不是尊重fetchBatchSize

是我想要的,如果是的话,我在这里做错了什么。如果使用fetchedResultsController无法做到这一点,那有什么替代方案?

fetchedResultsController:

class func transactionsResultController(wallet: Wallet, batchSize: Int? = nil) -> NSFetchedResultsController<Transaction> {
    let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
    let context: NSManagedObjectContext = appDelegate.managedObjectContext

    let fetchedResultsController: NSFetchedResultsController = { () -> NSFetchedResultsController<Transaction> in
        let fetchRequest: NSFetchRequest<Transaction> = Transaction.fetchRequest()

        fetchRequest.predicate = NSPredicate(format: "ANY wallet == %@", wallet)

        fetchRequest.fetchBatchSize = batchSize ?? 20

        let sortDescriptor = NSSortDescriptor(key: #keyPath(Transaction.timestamp), ascending: false)
        fetchRequest.sortDescriptors = [sortDescriptor]

        let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: "sectionIdentifier", cacheName: nil)

        do {
            try aFetchedResultsController.performFetch()
        } catch let error {
            debug(error)
        }
        return aFetchedResultsController
    }()

    return fetchedResultsController }

部分标识符:

extension Transaction{

var sectionIdentifier: String {
    let date = self.timestamp!.timestampToUTCDate(currency: (self.senderId?.currency!)!)
    let dateFormatter = DateFormatter()
    dateFormatter.timeZone = TimeZone(abbreviation: "en_US_POSIX")
    var components = DateComponents()
    let comps = Calendar.current.dateComponents([.year, .month, .day], from: date)
    components.day = comps.day
    components.month = comps.month
    components.year = comps.year
    let calendar = Calendar.current
    let reconstructedDate = calendar.date(from: components)!

    dateFormatter.dateFormat = "dd"
    let prettyDay = dateFormatter.string(from: reconstructedDate)
    dateFormatter.dateFormat = "MMMM"
    let prettyMonth = dateFormatter.string(from: reconstructedDate)
    dateFormatter.dateFormat = "YYYY"
    let prettyYear = dateFormatter.string(from: reconstructedDate)

    if (calendar.isDateInToday(reconstructedDate)){
        return "Today"
    }
    else if (calendar.isDateInYesterday(reconstructedDate)){
        return "Yesterday"
    }

    return "(prettyDay) (prettyMonth) (prettyYear)"
} }

感谢您花时间阅读和帮助;)

答案

fetchedResultsController不尊重batchSize。 fetchedResultsController通过使用谓词进行提取然后监视上下文来查看何时将项添加或删除到fetchedObjects列表并相应地更新。如果更改的项目通过谓词,但不在列表中,则它是插入;如果更改的项目未通过谓词,但在列表中,则为删除,否则为更新或移动。如果它遵守批量大小,那么fetchedResultsController将更难以知道传递谓词但是不在列表中的更改项目是插入还是传递batchSize的项目。

这有两种可能的解决方案:

  1. fetchedResultsController以batchSize限制获取所有内容。然后在您的UI中限制您显示的金额。不要通过在tableView中减少行来限制它(NUMBER_OF_ROWS - = min(REAL_NUMBER,SIZE_LIMIT)。有太多讨厌的边缘情况需要跟踪 - 比如推动和插入推送项目会从在底部列出,并为未显示的项目委托均匀。他们不是很难处理,但他们可以加起来,如果你搞砸了tableView将停止工作。只是声明,这是更容易indexPath高于某个索引的行高为0.这样您仍然可以像正常一样响应委托的fetchedResultsController事件,但UI不会显示单元格。
  2. 添加另一个谓词,将结果限制为所需的数量。例如,如果您的项目按日期排序,并且您只希望最近添加谓词“date> CUT_OFF_DATE”。要确定要使用的正确剪切日期,请执行单次提取,其中batchSize = 1且batchOffset等于您要显示的最大金额。然后在谓词中使用该对象的日期来创建fetchedResultsController。虽然限制将在控制器加载时受到尊重,但随着插入的项目越多,显示的数量将增加到超出初始显示限制。

如果你有很多项目,并希望限制进入内存的数量,第二个选项更好。

如果要限制每个部分中显示的数量(不仅仅是整个表的全局限制),那么第一个选项可以支持,但第二个选项不能。

以上是关于NSFetchedResultsController sectionNameKeyPath不尊重fetchBatchSize的主要内容,如果未能解决你的问题,请参考以下文章

在 Core Data 应用程序中调用 performFetch 后,是不是需要手动更新表视图?