2016-07-15 42 views
2

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


的例子假设一个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管理对象上下文(MOC)将由新的Product管理对象(MO)出售和使用。上述代码到目前为止工作正常。

但是!如果我结合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

回答

0

你可能会创建一个环形的所有权(保留周期)。

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

因此,它们不会被释放。

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

+0

为什么不应该按需要销毁/创建工作环境?例如。两个正在改变的MO尚未持续。如果在相同的环境下,一次保存将会持续两次 - 你可能只是想坚持其中的一次)。值得注意的CD堆栈出售多个工作者上下文(例如https://www.bignerdranch.com/blog/introducing-the-big-nerd-ranch-core-data-stack/)。 –

+0

@SOOverIt你说得对,我已经删除了我答案的最后部分。但是,您仍然需要确保您对所使用的任何托管上下文有强烈的参考。 – Sulthan

+0

您提到'每个托管对象都属于托管上下文'。这不完全正确。您仍然可以拥有已删除上下文的托管对象。请参阅NSManagedObject类参考中的managedObjectContext参考文档 (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/#//apple_ref/occ/instp/NSManagedObject/ managedObjectContext) - “如果接收方已从其上下文中删除,则可能为零。” –