Search code examples
iosswiftcore-datansfetchedresultscontrollerswift3

Difficulty configuring NSFetchedResultsController in Swift 3


I'm refactoring an existing project from Swift 2 to Swift 3. Everything has been straightforward until I got to refactoring Core Data. I'm able to create managed objects and persist them in the managedObjectContext, but I'm having difficulty getting NSFetchedResultsController to work. I took a look at this post, but it's not getting me across the finish line.

After importing records from a JSON, I verify there are objects in my managedObjectContext with the following code:

func recordCount() -> Int {
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "MyEntity")
    let count = try! context.count(for: fetchRequest)
    return count
}

When I create a fetchedResultsController, I'm running into trouble. My code doesn't crash, but it doesn't return NSManagedObjects despite there being objects that match my search.

Here's how I'm creating my NSFetchedResultsController in a UIViewController.

class MyViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate {
    // This is set on a prior viewController before segue.
    // I've verified it's not nil
    var selectedEquipmentString: String?

    let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

    lazy var fetchedResultsController: NSFetchedResultsController<MyEntity> = {
        // I've tried altering the syntax of the fetchRequest
        // let fetchRequest: NSFetchRequest<MyEntity> = MyEntity.fetchRequest()
        let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "MyEntity")
        let sortDescriptor = NSSortDescriptor(key: "generalArea", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]
        fetchRequest.predicate = NSPredicate(format: "equipmentDescription == %@", self.selectedEquipmentString!)
        let frc: NSFetchedResultsController<MyEntity> = NSFetchedResultsController(fetchRequest: fetchRequest as! NSFetchRequest<MyEntity>, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: "generalArea", cacheName: nil)
        frc.delegate = self
        return frc
    }()

    // MARK: - View Lifecycle Methods (abbreviated)
    override func viewDidLoad() {
        super.viewDidLoad()
        // I've tried moving this call to viewWillAppear and viewDidAppear without success
        fetchObjectsFromManagedObjectContext()
    }

    // MARK: - Core Data Methods (abbreviated)
    func fetchObjectsFromManagedObjectContext() {
        do {
            try fetchedResultsController.performFetch()
        } catch {
            print("error: \(error)")
            return
        }
        print ("There are \(fetchedResultsController.fetchedObjects!.count) returned from fetchObjectsFromManagedObjectContext")
    }
}

This code doesn't crash, but it doesn't return any records from a fetchRequest. I was able to force a crash with a typo in the predicate, but without a typo there are no objects returned despite objects that match the predicate.

I welcome any suggestions re: where my mistake is. I rest assured knowing it will be a startlingly silly oversight on my part. Thank you for reading.


Solution

  • Your NSFetchRequest should have a type NSFetchRequest<MyEntity>, but you specify NSFetchRequest<NSFetchRequestResult>. Try changing this and let me know if it helps or not