【问题标题】:Is fetchBachSize is really necessary or faults are substituted it?fetchBachSize 是真的有必要还是错误被替换了?
【发布时间】:2017-12-13 17:11:18
【问题描述】:

今天做简单测试的时候

 func testCountSales() {
    measureMetrics([XCTPerformanceMetric_WallClockTime],    automaticallyStartMeasuring: false, for: {
        let employee = self.getEmployees()
        let employeeDetails = EmployeeDetailViewController()
        self.startMeasuring()
        _ = employeeDetails.salesCountForEmployees(employee)
        self.stopMeasuring()
    })
}
func getEmployees() -> Employee {
    let coreDataStack = CoreDataStack(modelName: "EmployeeDirectory")
    let request: NSFetchRequest<Employee> = NSFetchRequest(entityName: "Employee")

    request.sortDescriptors = [NSSortDescriptor(key: "guid", ascending: true)]
    request.fetchBatchSize = 1
    let results: [AnyObject]?
    do {
        results = try coreDataStack.mainContext.fetch(request)
    } catch _ {
        results = nil
    }

    return results![0] as! Employee
}

我想知道 fetchBachSize 真的有效吗?我试图查看调试部分是完整的数组(应该是 50 个元素)。所有这些都是错误的。行。然后我尝试为 FetchedResultsController 的 fetchedObject 的计数属性添加观察者

  var window: UIWindow?
lazy var coreDataStack = CoreDataStack(modelName: "EmployeeDirectory")

let amountToImport = 50
let addSalesRecords = true

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]?) -> Bool {

    importJSONSeedDataIfNeeded()

    guard let tabController = window?.rootViewController as? UITabBarController,
        let employeeListNavigationController = tabController.viewControllers?[0] as? UINavigationController,
        let employeeListViewController = employeeListNavigationController.topViewController as? EmployeeListViewController else {
            fatalError("Application storyboard mis-configuration. Application is mis-configured")
    }

    employeeListViewController.coreDataStack = coreDataStack
    employeeListViewController.addObserver(self, forKeyPath: "fetchedResultsController", options: [.new], context: nil)

    guard let departmentListNavigationController = tabController.viewControllers?[1] as? UINavigationController,
        let departmentListViewController = departmentListNavigationController.topViewController as? DepartmentListViewController else {
            fatalError("Application storyboard mis-configuration. Application is mis-configured")
    }

    departmentListViewController.coreDataStack = coreDataStack

    return true
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "fetchedResultsController" {
        print ("Gold")
        let a = window?.rootViewController as? UITabBarController
        let employeeListNavigationController = a?.viewControllers?[0] as? UINavigationController
        let b = employeeListNavigationController?.topViewController as? EmployeeListViewController
       print( b?.fetchedResultsController.fetchedObjects?.count)
    }

}

它告诉我它是零,然后马上 50。显然它们也是错误的。那么为什么我们需要 fetchBatchSize 以及何时播放?如何?如果有人有任何想法,我将不胜感激

【问题讨论】:

    标签: ios swift core-data


    【解决方案1】:

    当您指定非零 fetchBatchSize 来请求核心数据时,将查询底层持久存储,并且在接收到结果时,只有结果数组的 fetchBatchSize 范围内的对象将被提取到内存中数组中的其他条目是页面错误。

    来自苹果的引述:

    如果您设置非零批量大小,则返回的对象集合 当 NSFetchRequest 的一个实例被执行时,被分成多个批次。 当 fetch 被执行时,整个请求被评估并且 记录所有匹配对象的身份,但仅记录对象的数据 最多为 batchSize 将从持久存储中获取 时间。执行请求返回的数组是代理对象 透明地根据需要对批次进行故障处理。 (在数据库方面,这 是内存中的游标。)

    例如,假设您的查询结果是一个包含 1000 个对象的数组,并且您将 fetchBatchSize 指定为 50。那么在 1000 个对象中,只有前 50 个将被转换为实际的对象/实体并加载到内存中。而剩下的 950 将只是一个页面错误。当您的代码尝试访问前 50 个对象时,将直接从内存中访问对象,而当您的代码尝试访问第 51 个对象时,因为内存中不存在对象(因此页面错误),核心数据将通过获取 next 来优雅地构造对象来自持久存储的一批数据并将其返回给您的代码。

    使用fetchBatchSize,您可以控制在处理大型数据集时在内存中处理的对象数量。

    它告诉我它是零,然后马上 50。显然他们 也是缺点。

    我相信您希望 FetchedResultsController 获取 1 个对象,因为您将 fetchBatchSize 指定为 1。但它最终获取了 50。所以您现在很困惑不是吗?

    fetchBatchSize 不会改变FetchedResultsController 的获取对象计数,它只会影响搜索结果中实际加载到内存中的对象数量。如果你真的想控制FetchedResultsController 获取的对象数量,你应该考虑使用fetchLimit

    阅读:

    https://developer.apple.com/documentation/coredata/nsfetchrequest/1506622-fetchlimit

    引自苹果:

    获取限制指定请求的最大对象数 执行时应该返回。如果设置获取限制,框架 尽最大努力提高效率,但不保证。 对于除 SQL 存储之外的每个对象存储,都会执行一个 fetch 请求 有效的提取限制只是执行无限制的提取和 丢弃未请求的行

    希望对你有帮助

    【讨论】:

    • fetchLimitfetchBatchSize 根本不受 FetchedResultsController 的尊重。 FetchedResultsController 需要将所有结果保存在内存中,以便知道何时删除或添加对象。
    • 乔恩·罗斯,你不知道它应该是苹果公司的还是一个错误?如果它应该是请可以“揭示”一些关于它的文档链接?我试图寻找它并感到困惑(
    • @n-khasanov : NSFetchedResultsController 不遵守 FetchLimit 是 NSFetchedResultsController 的一个已知错误。看到这个:stackoverflow.com/questions/4858228/… NSFetchedResultsController 仍然尊重fetchBatchSize。 NSFetchedResultsController 绝对不会将所有对象都加载到内存中,如果是这种情况人们会使用 Array 而不是 NSFetchedResultsController。 NSFetchedResultsController 的工作原理是页面错误,将数据从持久存储延迟加载到内存中。
    • @n-khasanov :FetchedResults 控制器仅将大小为 fetchBatchSize 的对象从持久存储加载到内存中,而对于其余结果,它会添加页面错误。这就是添加或删除对象时的情况。每次访问要删除/添加的对象时,您最终都会将对象提取到内存中。因此,显然 FetchedResults 控制器拥有对数据集执行添加、删除或移动操作所需的所有信息,这并不意味着 FetchedResults 控制器将结果中的所有对象加载到内存中。
    • 数组和 FetchedResults 控制器之间的主要性能差异是页面错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 2023-02-11
    • 2019-08-31
    • 1970-01-01
    • 2011-01-11
    • 2014-08-21
    相关资源
    最近更新 更多