0

Thanks for considering to help me! so I am getting this error in the console, How should I start going about fixing it?

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An instance of NSFetchedResultsController requires a non-nil fetchRequest and managedObjectContext'
*** First throw call stack:
(0x183ff51b8 0x182a2c55c 0x18630cb90 0x1000f4eb0 0x1000f46e8 0x1000f43c8 0x1000f411c 0x1000f40e4 0x101189218 0x10118a048 0x1000f41b4 0x1000fbb94 0x1000fbc94 0x189eaa924 0x189eaa4ec 0x18a2354e4 0x18a1fc6d0 0x18a1f8b44 0x18a13bfdc 0x18a12dd50 0x189e9d0b4 0x183fa20c0 0x183f9fcf0 0x183fa0180 0x183ece2b8 0x185982198 0x189f157fc 0x189f10534 0x1000f69d0 0x182eb15b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

These are the two swift files relevant to my error:

EntryController.swift

import Foundation
import CoreData

class EntryController {
    static let shared = EntryController()

    var fetchResultsController: NSFetchedResultsController<Entry>

    init() {
        let request: NSFetchRequest<Entry> = Entry.fetchRequest()
        let sortDescriptor = NSSortDescriptor(key: "timestamp", ascending: true)
        request.sortDescriptors = [sortDescriptor]
        fetchResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: CoreDataStack.context, sectionNameKeyPath: nil, cacheName: nil)
        (try? fetchResultsController.performFetch())
    }

    //CRUD
    func add(name: String, text: String) {
        _ = Entry(name: name, text: text)
        saveToPersistanceStorage()
    }

    func remove(entry: Entry) {
        let moc = CoreDataStack.context
        moc.delete(entry)
        saveToPersistanceStorage()
    }

    func update(entry: Entry, name: String, text: String) {
        entry.name = name
        entry.text = text
        saveToPersistanceStorage()
    }

    func saveToPersistanceStorage() {
        let moc = CoreDataStack.context
        (try? moc.save())
    }
}

EntryTableListViewController.swift

import UIKit
import CoreData

class EntrylistTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        EntryController.shared.fetchResultsController.delegate = self
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        guard let entries = EntryController.shared.fetchResultsController.fetchedObjects else {return 0}
        return entries.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "entryCell", for: indexPath)
        let entry = EntryController.shared.fetchResultsController.object(at: indexPath)
        cell.textLabel?.text = entry.name
        return cell
    }
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            let entry = EntryController.shared.fetchResultsController.object(at: indexPath)
            EntryController.shared.remove(entry: entry)
        }
    }

    //MARK: NSFetchedResultsControllerDelegate
    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {

        switch type {
        case .insert:
            guard let newIndexPath = newIndexPath else {return}
            tableView.insertRows(at: [newIndexPath], with: .automatic)
        case .delete:
            guard let indexPath = indexPath else {return}
            tableView.deleteRows(at: [indexPath], with: .automatic)
        case .move:
            guard let indexPath = indexPath, let newIndexPath = newIndexPath else {return}
            tableView.deleteRows(at: [indexPath], with: .automatic)
            tableView.insertRows(at: [newIndexPath], with: .automatic)
        case .update:
            guard let indexPath = indexPath else {return}
            tableView.reloadRows(at: [indexPath], with: .automatic)
        }
    }

    // MARK: - Navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "toDetailSegue" {
            if let detailVC = segue.destination as? EntryDetailViewController,
                let selectedRow = tableView.indexPathForSelectedRow {
                let entry = EntryController.shared.fetchResultsController.object(at: selectedRow)
                detailVC.entry = entry
            }
        }
    }
}

The app creates that error as soon as the button is pressed from the main menu to segue into the EntryTableListViewController.swift. Any help will be greatly appreciated!

Additionally, here's my CoreDataStack code

import Foundation
import CoreData

enum CoreDataStack{


    static let container: NSPersistentContainer = {

        let appName = Bundle.main.object(forInfoDictionaryKey: (kCFBundleNameKey as String)) as! String

        let container = NSPersistentContainer(name: appName)
        container.loadPersistentStores() { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
        return container
    }()

    static var context: NSManagedObjectContext { return container.viewContext }
}
  • Set a breakpoint in your `init` And check but I suspect that your managed object context is nil – Paulw11 Aug 06 '17 at 22:53
  • @Paulw11 I can't make an if statement to check for nil, as NSManagedObjectContext is a non optional – Shane Curtis Aug 06 '17 at 23:05
  • No, you need to work through the more fundamental issue as to why the context is `nil`; it seems that it hasn't been initialised before you are creating your `EntryController` object. Or the crash may be somewhere else; you haven't indicated which line the exception occurred on; set an exception breakpoint. Perhaps add your `CoreDataStack` code, at least as far as the definition of `context` is concerned – Paulw11 Aug 06 '17 at 23:48
  • @Paulw11 Sorry for leaving vital information out, I am still a novice programmer. The exception points to this line of code in the viewDidLoad in the tableViewController file: EntryController.shared.fetchResultsController.delegate = self ; and also in the EntryController file at this line: static let shared = EntryController() – Shane Curtis Aug 06 '17 at 23:59
  • Set a breakpoint on the line `let appName = ` and step through - is your core data stack being initialised correctly? – Paulw11 Aug 07 '17 at 00:58

0 Answers0