2016-07-15 91 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) - 「如果接收方已從其上下文中刪除,則可能爲零。」 –