NSObjectInaccessibleException - 删除所有实体对象 - NSFetchedResultsController

时间:2015-02-02 19:40:10

标签: ios swift core-data nsfetchedresultscontroller

我有一个功能负责删除实体的所有项目:

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

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

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

        for result in results as [NSManagedObject] {
            managedContext.deleteObject(result)
        }

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

我的应用程序包含一个带有3个屏幕的TabBar:

第一个标签显示城市列表,当选择一个城市时,会执行一个segue并转到产品列表页面,用户可以在其中标记"标记"产品

第二个标签有一个显示这些品牌产品列表的屏幕,还有一个显示产品数量的徽章

但是,每当用户选择其他城市或终止后启动应用程序时,我都需要删除该实体的所有对象。

对于第一种情况,我删除" prepareForSegue"中的所有对象。当用户选择一个城市时它起作用,并且它完美地运作。

当我尝试运行第二种情况时出现问题。 如果我尝试在"应用程序中调用remove函数didFinishLaunchingWithOptions" AppDelegate或" viewDidLoad"在第一个标签中,银行已损坏,当我尝试进入第二个标签时收到以下消息:

由于未捕获的异常终止应用' NSObjectInaccessibleException',原因:' CoreData无法解决' 0xd000000000140000''

但是如果我删除" application didFinishLaunchingWithOptions"的功能。或" viewDidLoad"第一个选项卡,应用程序运行良好。

仔细观察,错误发生在第二个标签(产品列表)中。

我有一个变量用于跟踪表格中的项目(在第二个标签中):

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
}()

错误正好发生在第二个标签的这一行:

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

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

有人会对我做错了什么有任何建议吗?

1 个答案:

答案 0 :(得分:0)

问题完全在第二个标签中。

问题的答案是删除变量:

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

现在“viewDidLoad”第二个标签如下(删除了提取):

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

添加了以下变量:

var entities = [Entidade]()

并添加了以下方法:

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

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.entities = results
    } else {
        println("Could not fetch \(error), \(error!.userInfo)")
    }
}

通过这些更改,我可以在应用程序启动时通过将以下代码放在城市列表屏幕中来删除对象:

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

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

或者在应用程序启动或结束时选择在AppDelegate中调用“removeItems()”方法。

如果有人需要,我可以发布屏幕的完整源代码。

<强>更新

我发现了实际发生的事情,我在AppDelegate中有一个方法,负责在用户标记产品时更新列表的“badgeValue”标签。

他如下(每次在managedObjectContext中发生更改时都会调用):

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

    if let tabBarViewControllers = tabBarController.viewControllers {
        let navigationController = tabBarViewControllers[3] as UINavigationController
        let listViewController = navigationController.viewControllers[0] as ListViewController
        listViewController.managedObjectContext = managedObjectContext // <--- Here's the problem

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

我无法以这种方式将managedObjectContext设置为屏幕,我只需要在“application didFinishLaunchingWithOptions”中分配一次,所以我必须保留旧代码以利用NSFetchedResultsController