Проблемы освобождения NSManagedObjectContext - (Swift | Связанные объекты)
Я надеюсь, что кто-то может объяснить, почему связанные объекты в следующем примере не освобождаются автоматически при освобождении объекта источника / хоста. Этот пример кода ниже несколько надуманный (заранее извиняюсь), но он объясняет мою проблему.
В примере предполагается, что сущность CoreData Product
со строковым атрибутом sku
и стек CoreData по умолчанию, предоставленный шаблоном Xcode:
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
При выполнении этой функции новый контекст управляемого объекта (MOC) PrivateQueueConcurrencyType будет передан и использован новым Product
Управляемый объект (МО). Этот код выше работает правильно - пока.
Тем не мение! если я объединю первые две строки 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
}
Кажется, это прекрасно работает - пока я не проверю инструменты. Казалось бы, когда Product
MO освобожден, а теперь связанный MOC - нет (не должен ли он быть автоматически освобожден, когда исходный объект освобожден?)
Мой вопрос: может ли кто-нибудь объяснить, где дополнительная ссылка на MOC, которая препятствует его освобождению? Создал ли я цикл сохранения между МО и МОК?
1 ответ
Вы, вероятно, создаете круговую собственность (сохраняете цикл).
Каждый управляемый объект принадлежит управляемому контексту (контекст владеет объектом), и установка контекста в качестве связанного объекта означает, что объект теперь также владеет контекстом.
Поэтому они не будут освобождены.
Реальное решение - сохранить фоновый контекст в локальном свойстве, то же самое, что вы делаете с mainContext
,