NSFetchedResultsController sectionNameKeyPath不尊重fetchBatchSize

时间:2017-12-19 20:03:08

标签: swift core-data

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

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

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

fetchedResultController:

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

感谢您花时间阅读并提供帮助;)

1 个答案:

答案 0 :(得分:0)

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&gt; CUT_OFF_DATE”。要确定要使用的正确剪切日期,请执行单次提取,其中batchSize = 1且batchOffset等于您要显示的最大金额。然后在谓词中使用该对象的日期来创建fetchedResultsController。虽然限制将在控制器加载时受到尊重,但随着插入的项目越多,显示的数量将增加到超出初始显示限制。

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

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