NSManagedObjectContext解除分配问题-(Swift关联对象)

NSManagedObjectContext解除分配问题-(Swift关联对象),swift,core-data,associated-object,Swift,Core Data,Associated Object,我希望有人能解释为什么在源/主机对象解除分配时,以下示例中的关联对象不会自动解除分配。下面的示例代码有点做作(提前道歉),但它解释了我的问题 该示例假定CoreData实体产品,具有字符串属性sku,并且默认CoreData堆栈由Xcode模板提供: import UIKit import CoreData class ViewController: UIViewController { @IBAction func createProduct(sender: AnyObject)

我希望有人能解释为什么在源/主机对象解除分配时,以下示例中的关联对象不会自动解除分配。下面的示例代码有点做作(提前道歉),但它解释了我的问题


该示例假定CoreData实体
产品
,具有字符串属性
sku
,并且默认CoreData堆栈由Xcode模板提供:

import UIKit
import CoreData

class ViewController: UIViewController {

    @IBAction func createProduct(sender: AnyObject) {

        let context = CoreDataHelpers.vendBackgroundWorkerContext()
        let newProduct = CoreDataHelpers.newProduct(context: context)

        newProduct.sku = "8-084220001"

        do {
            try newProduct.managedObjectContext?.save()
            print("Product created [SKU: \(newProduct.sku ?? "NotDefined")]")
        } catch {
            print(error)
        }
    }
}


public class CoreDataHelpers {

    public static let mainContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

    public class func vendBackgroundWorkerContext() -> NSManagedObjectContext {
        let managedObjectContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
        managedObjectContext.parentContext = self.mainContext

        return managedObjectContext
    }

    class func newProduct(context context: NSManagedObjectContext) -> Product {
        let newProduct = NSEntityDescription.insertNewObjectForEntityForName("Product", inManagedObjectContext: context) as! Product

        return newProduct
    }

}
执行
createProduct
功能时,新的
Product
托管对象(MO)将出售并使用新的PrivateQueueConcurrencyType托管对象上下文(MOC)。到目前为止,上述代码工作正常

然而!如果我将
createProduct
函数的前两行组合在一起,则:

let newProduct = CoreDataHelpers.newProduct(context: CoreDataHelpers.vendBackgroundWorkerContext())
然后应用程序将在
使用
EXC\u BAD\u访问权限尝试newProduct.managedObjectContext?.save()
时崩溃

乍一看,这似乎有点奇怪——因为我们所做的只是重构代码。深入到中,
managedObjectContext
属性被声明为
无主(不安全)
。这可能意味着创建的MOC已被解除分配,我们有一个悬空的指针(如果我的假设是错误的,请纠正我)

为了确保MOC不会被解除分配,我尝试将其与MO本身关联<代码>新产品

class func newProduct(context context: NSManagedObjectContext) -> Product {
    let newProduct = NSEntityDescription.insertNewObjectForEntityForName("Product", inManagedObjectContext: context) as! Product

    var key: UInt8 = 0
    objc_setAssociatedObject(newProduct, &key, context, .OBJC_ASSOCIATION_RETAIN)

    return newProduct
}
这似乎工作得很好-直到我检查仪器。当
产品
MO被解除分配时,现在关联的MOC不会被解除分配(当源对象被解除分配时,它不应该被自动解除分配吗?)

我的问题是: 有人能解释一下,额外的参考是指阻止其被解除分配的主运行中心吗?我是否在MO和MOC之间创建了保留周期?


您可能正在创建一个循环所有权(保留周期)

每个托管对象都属于托管上下文(上下文拥有该对象),将上下文设置为关联对象意味着该对象现在也拥有该上下文

因此,它们不会被解除分配


真正的解决方案是将背景上下文保存到本地属性,这与使用
mainContext

时所做的相同。为什么不应按需销毁/创建工作上下文?两个正在更改但尚未持久化的MOs。如果在同一上下文中,保存将同时保留两个MOs(您可能只想保留其中一个)。值得注意的CD堆栈出售多个工作上下文(例如)。@SoOverIt如果你是对的,我已经删除了我答案的最后一部分。但是,您仍然必须确保对正在使用的任何托管上下文都有强引用。您提到“每个托管对象都由托管上下文拥有”。这并不完全正确。您仍然可以拥有已删除上下文的托管对象。请参阅NSManagedObject类引用()中有关managedObjectContext的文档-“如果接收器已从其上下文中删除,则可能为零。”@soovrit是的,但托管对象将变得不可用。你不能再保存它并从中读取数据了。非常正确。它确实变得无法使用了。这就是为什么我希望托管对象上下文保持不变。