我希望有人可以解释为什么在解除分配源/主机对象时,以下示例中的关联对象不会自动解除分配。下面的示例代码有点 人为设计 (提前道歉),但它解释了我的问题。
该示例假定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
时崩溃。
乍一看,这看起来有点奇怪 - 因为我们所做的就是重构代码。深入documentation,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
}
这似乎很有效 - 直到我检查仪器。看来当Product
MO被释放时,现在关联的MOC不是(当源对象被解除分配时,不应该自动解除分配吗?)
我的问题是: 有人可以解释一下MOC的附加引用在哪里阻止它被解除分配吗?我是否在MO和MOC之间创建了保留周期?
答案 0 :(得分:0)
您可能正在创建循环所有权(保留周期)。
每个托管对象都由托管上下文拥有(上下文拥有该对象),并将上下文设置为关联对象意味着该对象现在也拥有该上下文。
因此,他们不会被解除分配。
真正的解决方案是将背景上下文保存到本地属性,就像使用mainContext
一样。