Search code examples
swiftmultithreadingcore-datansfetchedresultscontrollerdispatch-async

how to load the Core Data in background thread


i have some big data in my Core Data store how can i load this data in background thread?

    func connectionCoreData() {
        let fetchRequest = NSFetchRequest<PersonalClass>(entityName: "PersonalBase")
        let sortDescriptor = NSSortDescriptor(key: "personName", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]
        if let managerObjectContext = (UIApplication.shared.delegate as? AppDelegate)?.managedObjectContext {
            fetchResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managerObjectContext, sectionNameKeyPath: nil, cacheName: nil)
            fetchResultController.delegate = self
            do {
                try fetchResultController.performFetch()
                personalArray = fetchResultController.fetchedObjects!
                self.tableView.reloadData()
            } catch {
                print(error)
            }
        }
    }

i need add core data load in background thread and then update my tableView


Solution

  • First, you should put in mind that a managedObjectContext runs on a single thread. And you should access/edit the loaded objects on the same thread.

    In your case, you will interact with the objects that you are going to load on the main thread. For example, the loaded database objects will fill a tableView and this should be done on the main thread. This forces the managedObjectContext to be of MainContextType which runs on the main thread.

    http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html

    You should not be afraid of running the NSFetchedResultsController on the main thread because it loads the objects in batches. However, you aren't using the FetchedResults Controller as it should. You shouldn't have these two lines in your code.

    personalArray = fetchResultController.fetchedObjects!
    self.tableView.reloadData()
    

    You should access the loaded object using this method fetchResultController .objectAtIndexPath(indexPath).

    This is an example of how to use the NSFetchedResultsController

    class ViewController: UITableViewController NSFetchedResultsControllerDelegate{
    
        lazy var fetchedResultsController: NSFetchedResultsController = {
            let fetchRequest = ... //Create the fetch request
            let sortDescriptor = ... //Create a sortDescriptor
            let predicate = ...//Create the predicate if you want to filter the results
            fetchRequest.predicate = predicate
    
            let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: mainContext, sectionNameKeyPath: nil, cacheName: nil)
            fetchedResultsController.delegate = self
            return fetchedResultsController
        }()
    
        override fun viewDidLoad(){
             super.viewDidLoad()
             do {
                 try self.fetchedResultsController.performFetch()
             }catch {
                 print(error)
             }
        }
    
        func controllerWillChangeContent(controller: NSFetchedResultsController) {
            tableView.beginUpdates()
        }
    
        func controllerDidChangeContent(controller: NSFetchedResultsController) {
            tableView.endUpdates()
        }
    
        func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
            switch (type) {
            case .Insert:
                if let indexPath = newIndexPath {
                    tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
                }
                break;
            case .Delete:
                if let indexPath = indexPath {
                    tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
                }
                break;
            case .Update:
                if let indexPath = indexPath {
                    tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
                }
                break;
            case .Move:
                if let indexPath = indexPath, newIndexPath = newIndexPath {
                    tableView.moveRowAtIndexPath(indexPath, toIndexPath: newIndexPath)
                }
                break;
            }
        }
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            if let sections = fetchedResultsController.sections {
                let sectionInfo = sections[section]
                return sectionInfo.numberOfObjects
            }
            return 0
        }
    
       override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
           let obj = fetchedResultsController.objectAtIndexPath(indexPath){
           ....
        }
    
    }