NSManagedObjectContext释放问题 - (Swift |关联对象)

时间:2016-07-15 05:32:14

标签: swift core-data associated-object

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

该示例假定CoreData实体Product具有字符串属性sku和Xcode模板提供的默认CoreData堆栈:

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

然后,应用会在try newProduct.managedObjectContext?.save() EXC_BAD_ACCESS时崩溃。

乍一看,这看起来有点奇怪 - 因为我们所做的就是重构代码。深入documentationmanagedObjectContext属性被声明为unowned(unsafe)。这可能意味着已创建的MOC已被解除分配,并且我们有一个悬空指针(如果我的假设错误,请纠正我。)

为了确保MOC不被取消分配,我尝试将其与MO本身相关联。 newProduct

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
}

这似乎很有效 - 直到我检查仪器。看来当Product MO被释放时,现在关联的MOC不是(当源对象被解除分配时,不应该自动解除分配吗?)

我的问题是: 有人可以解释一下MOC的附加引用在哪里阻止它被解除分配吗?我是否在MO和MOC之间创建了保留周期?

enter image description here

1 个答案:

答案 0 :(得分:0)

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

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

因此,他们不会被解除分配。

真正的解决方案是将背景上下文保存到本地属性,就像使用mainContext一样。