Проблемы освобождения 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,

Другие вопросы по тегам