5

I have been having problems with fetchBatchSize in an NSFetchedResultsController so I decided to take a step back and use it on just a plain NSFetchRequest. I created a very simple project with only a tableViewController that has 100 items. The items have only two properties, itemID and itemName. I use the following method to populate the data array:

func initializeItems() {
        let request = NSFetchRequest<Item>(entityName: "Item")
        let messageSort = NSSortDescriptor(key: "itemName", ascending: true)
        request.sortDescriptors = [messageSort]
        request.fetchBatchSize = 20
        do {
            let fetchedResults = try context.fetch(request)
            if fetchedResults.count > 0 {
                self.items = fetchedResults
                //self.tableView.reloadData()
            }
        } catch {
            print("Could not fetch \(error)")
        }
    }

This is called in viewDidLoad of the tableViewController. The context is defined as follows:

let appDelegate = UIApplication.shared.delegate as! AppDelegate
self.context = appDelegate.persistentContainer.viewContext

When I run the app, the table shows fully populated (as indicated by the scroll bar) with all rows.

I don't understand why the fetchBatchSize is being ignored.

Documentation is as follows:

The batch size of the objects specified in the fetch request. The default value is 0. A batch size of 0 is treated as infinite, which disables the batch faulting behavior. If you set a nonzero batch size, the collection of objects returned when an instance of NSFetchRequest is executed is broken into batches. When the fetch is executed, the entire request is evaluated and the identities of all matching objects recorded, but only data for objects up to the batchSize will be fetched from the persistent store at a time. The array returned from executing the request is a proxy object that transparently faults batches on demand. (In database terms, this is an in-memory cursor.) You can use this feature to restrict the working set of data in your application. In combination with fetchLimit, you can create a subrange of an arbitrary result set.

I can see the 100 items in the fault array being loaded. But then it loops through 5 loads of 20 items full data prior to scrolling the tableView. The tableView shows about 15 rows at a time.

The behaviour I want is for the data to be loaded in 20 item batches as the table is scrolled

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
alionthego
  • 8,508
  • 9
  • 52
  • 125
  • 1
    fetchBatchSize mean it will load all data, but step by step (paging by batchsize). If you want to load only 20 item, you can using fetchLimit – Quoc Nguyen Jun 07 '18 at 06:44
  • You should use `fetchLimit` to limit the number of recored. – Sandeep Kumar Jun 07 '18 at 06:46
  • fetchBatchSize should load all entries only by the objectID into a fault array and populate them by the batch size you enter when you scroll down and ask for more rows (automatic on nsfetchedresultscontroller). here the 100 row fault array is loaded and then all rows and their data is being loaded right away in 5 separate 20 row batches prior to scrolling. it is for some reason looping through the 5 20 batch loads right away. – alionthego Jun 07 '18 at 08:55
  • Did you find the answer to your question? I faced the same observation. – Aisha Jul 16 '20 at 19:50

3 Answers3

0

As shown in the documentation:

The fetch limit specifies the maximum number of objects that a request should return when executed.

fetchLimit is what you're looking for.

ChavirA
  • 707
  • 8
  • 18
  • I’m very familiar with fetchLimit and that is not what I’m looking for. I’m looking to use fechBatchSize – alionthego Jul 12 '18 at 05:19
0

I suspect something in your code actually iterates through that array and causes it to fire the fault. I'm not telling you do it deliberately yourself - it is quite likely that setup od your UITableView does that (pre-calculating cell height based on content, sectioning data, etc).

What I suggest is to open Core Data profiling tool in Instruments and check what is in the stack trace when faults are fired.

deekay
  • 899
  • 6
  • 8
0

fetchBatchSize works best with NSFetchedResultsController. Put ur fetchRequest in NSFetchedResultsController and then use NSFetchedResultsController to access fetched result. Then definitely fetchBatchSize gonna work. Or u can google how NSFetchedResultsController is implemented in fetching result.

helpMe
  • 1