NSObjectInaccessibleException - Deleting all objects from an entity - NSFetchedResultsController

1

I have a function responsible for deleting all the items of an entity:

func removeItens() {
    if let managedContext = managedObjectContext {
        let fetchRequest = NSFetchRequest()

        let entity = NSEntityDescription.entityForName("Entidade", inManagedObjectContext: managedContext)
        fetchRequest.entity = entity
        fetchRequest.includesPropertyValues = false

        var error: NSError?
        var resultados = managedContext.executeFetchRequest(fetchRequest, error: &error)

        for resultado in resultados as [NSManagedObject] {
            managedContext.deleteObject(resultado)
        }

        if !managedContext.save(&error) {
            println("could not save \(error), \(error?.userInfo)")
        }
    }
}

My application consists of a TabBar with 3 screens:

On the first tab, I have a list of cities, and on selecting the user is sent to a product listing screen, where he can "tag" the products.

The second tab has a screen that shows the listing of these marked products.

However, I need to delete all objects in this entity whenever the user selects a different city or when it starts the application after it is finished.

For the first case, I call the function in the "prepareForSegue" when the user selects a city, and it works perfectly.

The problem arises when I try to run in the second case. If I try to call this function in AppDelegate's "application didFinishLaunchingWithOptions" or in the "viewDidLoad" of the first tab, the database is corrupted, and I get the following message when I try to enter the second tab:

Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for' 0xd000000000140000 ''

However, if I remove the function from the "application didFinishLaunchingWithOptions" or "viewDidLoad" from the first tab, the application works perfectly.

== Updated ==

Watching more closely, the error is occurring in the second tab (the product listing).

I have a variable in which I use to keep the table items up to date (if the user marks a product).

lazy var fetchedResultsController: NSFetchedResultsController = {
    let fetchRequest = NSFetchRequest()

    let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
    let managedContext = appDelegate.managedObjectContext!

    let entity = NSEntityDescription.entityForName("Entidade", inManagedObjectContext: managedContext)
    fetchRequest.entity = entity

    let sortDescriptor1 = NSSortDescriptor(key: "nome", ascending: true)
    fetchRequest.sortDescriptors = [sortDescriptor1]

    let fetchedResultsController = NSFetchedResultsController(
        fetchRequest: fetchRequest,
        managedObjectContext: managedContext,
        sectionNameKeyPath: "nome",
        cacheName: "Entidade")

    fetchedResultsController.delegate = self
    return fetchedResultsController
}()

And the error is occurring exactly on this line:

override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.leftBarButtonItem = editButtonItem()

    var error: NSError?
    if !fetchedResultsController.performFetch(&error) { // <----- Esta
        fatalCoreDataError(error)
    }
}

Would anyone have any suggestions?

    
asked by anonymous 02.02.2015 / 15:30

1 answer

1

The problem was entirely on the second tab.

The answer to the problem was to remove the variable:

lazy var fetchedResultsController: NSFetchedResultsController = {
    .
    .
    .
}()

Now the "viewDidLoad" of the second tab looks as follows (fetch removed):

override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.leftBarButtonItem = editButtonItem()
}

The following variable has been added:

var entidades = [Entidade]()

And the following methods are added:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    fetchLog()
}

E

func fetchLog() {
    let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
    let managedContext = appDelegate.managedObjectContext!

    let request = NSFetchRequest(entityName: "Entidade")

    var error: NSError? = nil

    if let results = managedContext.executeFetchRequest(request, error: &error) as? [Entidade] {
        self.entidades = results
    } else {
        println("Could not fetch \(error), \(error!.userInfo)")
    }
}

With these changes, I can finally remove the items when the application is started by placing the following code in the city listing screen:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
    appDelegate.removeItens()
}

Or choose to call the "removeItens ()" method in AppDelegate when the application starts or ends.

If someone needs it, I can post the entire source code of the screens.

Updated

I discovered what actually happened, I have a method in the AppDelegate where it is responsible for updating the "badgeValue" of the listing tab, whenever a user tags a product.

It was as follows (and was called every time there was a change in the managedObjectContext):

func atualizaUI() {
    let tabBarController = window!.rootViewController as UITabBarController

    if let tabBarViewControllers = tabBarController.viewControllers {
        let navigationController = tabBarViewControllers[3] as UINavigationController
        let listaViewController = navigationController.viewControllers[0] as ListaViewController
        listaViewController.managedObjectContext = managedObjectContext // <--- Aqui está o problema

        let fetchRequest = NSFetchRequest(entityName: "Entidade")
        if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) {
            navigationController.tabBarItem.badgeValue = String(fetchResults.count)
        }
    }
}

I can not set the managedObjectContext to a screen in this way, I need to assign it a single time in the "application didFinishLaunchingWithOptions", so I was able to keep the previous code to be able to take advantage of the NSFetchedResultsController

    
02.02.2015 / 23:17