2

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


该示例假定 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函数被执行时,一个新的 PrivateQueueConcurrencyType Managed Object Context (MOC) 将被新的ProductManaged Object (MO) 出售和使用。上面的代码工作正常 - 到目前为止。

然而!如果我将createProduct函数的前两行组合起来:

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

然后应用程序将崩溃并try newProduct.managedObjectContext?.save()带有EXC_BAD_ACCESS.

乍一看,这似乎有点奇怪——因为我们所做的只是重构了代码。深入研究文档,该managedObjectContext属性被声明为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
}

这似乎非常有效 - 直到我签入 Instruments。看起来,当ProductMO 被释放时,现在关联的 MOC 不是(当源对象被释放时不应该自动释放吗?)

我的问题是:有人可以解释阻止它被释放的 MOC 的附加参考在哪里吗?我是否在 MO 和 MOC 之间创建了保留周期?

在此处输入图像描述

4

1 回答 1

1

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

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

因此,它们不会被释放。

真正的解决方案是将背景上下文保存到本地属性,就像您对mainContext.

于 2016-07-15T06:03:04.603 回答