为啥在一个视图中有不同的上下文?

Posted

技术标签:

【中文标题】为啥在一个视图中有不同的上下文?【英文标题】:Why different different contexts in one view?为什么在一个视图中有不同的上下文? 【发布时间】:2015-11-11 21:55:59 【问题描述】:

我有一个购物车控制器。用户可以将项目添加到他的愿望清单中。如果我们没有任何愿望清单,我们应该创建默认清单。这是工作 2-3 次,如果我添加,然后删除,然后再添加。然后我得到错误:

非法尝试在对象之间建立关系“wishList” 在不同的情况下

class CartViewController: UIViewController, NSFetchedResultsControllerDelegate 
        var fetchResultController:NSFetchedResultsController!
        var shopItems:[ShopItem] = []
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

        override func viewDidLoad() 
             self.fetchResultController = NSFetchedResultsController(fetchRequest: fetchRequest,
                    managedObjectContext: self.appDelegate.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
            self.fetchResultController.delegate = self
            do 
                try fetchResultController.performFetch()
                self.shopItems = fetchResultController.fetchedObjects as! [ShopItem]
             catch 
                fatalError("Failure to save context: \(error)")
            

        
        func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? 

            let addToWishListAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Add to wish list", handler:  (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
                var wishListResults:[WishList] = []
                let fetchRequest = NSFetchRequest(entityName: "WishList")
                var wishList:WishList
                fetchRequest.fetchLimit = 1

                //...some other code

                wishList = NSEntityDescription.insertNewObjectForEntityForName("WishList", inManagedObjectContext: self.appDelegate.managedObjectContext) as! WishList
                wishList.setValue("Default wish list", forKey: "title")
                wishList.setValue("My wish list", forKey: "desc")

                let shopItem = self.fetchResultController.objectAtIndexPath(indexPath) as! ShopItem

                shopItem.setValue(true, forKey: "inWishList")
                shopItem.setValue(wishList, forKey: "WishList")

                do 
                    try self.appDelegate.managedObjectContext.save()
                 catch 
                    fatalError("Failure to save context: \(error)")
                
            )
        
    

为什么上下文改变了?

【问题讨论】:

【参考方案1】:

您正试图在与创建托管对象上下文不同的线程上创建和保存 CoreData 对象。 UITableViewRowAction 的处理程序提供了一个块回调,它将在不同的线程上异步发生。

为了在不同的线程上创建和保存对象,您需要创建另一个 NSManagedObjectContextconcurrencyType PrivateQueueConcurrencyType,然后在后台线程中使用它。

这就是我将如何重写您的editActionsForRowAtIndexPath 方法(因为每个人都想复制和粘贴,对吧?):

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? 

    let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
    privateMOC.parentContext = self.appDelegate.managedContext
    let addToWishListAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Add to wish list", handler:  (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
        var wishListResults:[WishList] = []
        let fetchRequest = NSFetchRequest(entityName: "WishList")
        var wishList:WishList
        fetchRequest.fetchLimit = 1

        //...some other code

        wishList = NSEntityDescription.insertNewObjectForEntityForName("WishList", inManagedObjectContext: privateMOC) as! WishList
        wishList.setValue("Default wish list", forKey: "title")
        wishList.setValue("My wish list", forKey: "desc")

        let shopItem = self.fetchResultController.objectAtIndexPath(indexPath) as! ShopItem

        shopItem.setValue(true, forKey: "inWishList")
        shopItem.setValue(wishList, forKey: "WishList")

        do 
            try privateMOC.save()
         catch 
            fatalError("Failure to save context: \(error)")
        
    )

另外,请确保您正在创建 ManagedObjectContext 以将 MainQueueConcurrencyType 用作:

var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)

【讨论】:

> 另外,请确保您正在创建 ManagedObjectContext 以使用 MainQueueConcurrencyType 作为:您的意思是替换它:let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate ??因为我在每个控制器中都使用它?这正常吗? 现在我每次都收到错误Illegal attempt to establish a relationship。没有帮助 这个答案实际上并没有解决线程问题,真正的问题是您在 2 个上下文中混合对象

以上是关于为啥在一个视图中有不同的上下文?的主要内容,如果未能解决你的问题,请参考以下文章

选中列表视图上的复选框时,为啥不激活上下文操作栏?

为啥我们将视图和上下文对象作为函数中的参数传递,API 22 [关闭]

为啥我会得到:非法尝试在不同上下文中的对象之间建立关系...

绑定到两个不同视图的数据源。 MVVM,WPF

为啥这个 Django 模板没有接收到上下文?

为啥在 XAML 中绑定 MainWindow 数据上下文与使用 this.datacontext=this 在代码隐藏中绑定的行为不同?