Изменить NSManagedObjectContext по умолчанию для NSPersistentDocument

Новичок в основных данных здесь. Я пытаюсь изменить значение по умолчанию NSManagedObjectContext для NSPersistentDocument, чтобы инициализировать и использовать его с NSMainQueueConcurrencyType.

В настоящее время я делаю это в -windowControllerDidLoadNib: следующим образом:

- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
    [super windowControllerDidLoadNib:aController];
    NSManagedObjectContext *newMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [newMOC setPersistentStoreCoordinator:[self.managedObjectContext persistentStoreCoordinator]];
    [self setManagedObjectContext:newMOC];
}

Это, казалось бы, работает нормально. Но мне интересно, лучше ли инициализировать MOC в -windowControllerDidLoadNib:, или его следует разместить где-то еще и/или инициализировать по-другому.

Спасибо за любую помощь.


person insys    schedule 23.03.2014    source источник


Ответы (2)


Предпочтительным шаблоном является подход "передать эстафету", когда вы передаете контекст управляемого объекта дочерним контроллерам представления. Дайте вашим контроллерам атрибут контекста управляемого объекта и просто передайте его, когда вы их представляете.

person Mundi    schedule 23.03.2014
comment
Но иногда вам может понадобиться дочерний MOC для простого возврата. В этом случае метод передачи эстафетной палочки не сработает. - person vomi; 29.10.2019

Я экспериментирую с шаблоном Xcode для приложения CoreData на основе документов. Шаблон создает переопределение init(), которое просто вызывает super.init(). Я хочу запустить большой импорт в фоновом режиме, поэтому я добавил это в класс документа:

class Document: NSPersistentDocument {

    private var importQueue = DispatchQueue(label: "Importer")

    override init() {
        super.init()

        let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        moc.mergePolicy = self.managedObjectContext!.mergePolicy
        moc.persistentStoreCoordinator = self.managedObjectContext!.persistentStoreCoordinator
        self.managedObjectContext = moc
    }

    func importStuff(url: URL) {

        let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        moc.parent = self.managedObjectContext

        var count = 0

        moc.performAndWait {
            ...

            count += 1
            if count % 10000 == 0 {
                do {
                    try moc.save()
                    moc.reset()
                }
                catch {
                    Swift.print("save failed at record #\(count): \(error.localizedDescription)")
                }
            }
            return true
        }

        do {
            try moc.save()
        }
        catch {
            Swift.print("save failed at records #\(count): \(error.localizedDescription)")
        }

    }

    Swift.print("imported \(count) records.")
}

@IBAction func import(_ sender: Any) {

        ...

        importQueue.async {
            self.importStuff(url: url)
        }
    }
}

Кажется, это работает нормально в моих первоначальных тестах. Я думаю, что инициализация нового MOC в -windowControllerDidLoadNib: — это нормально, но если у вас есть объектные контроллеры, привязанные к MOC документа, они могут выполнить вторую выборку при изменении MOC. Инициализация его в init приведет к его инициализации раньше, до загрузки пользовательского интерфейса.

person Aaron Burghardt    schedule 18.03.2017
comment
Проверено, и это работает. Я думаю, что это должен быть принятый ответ. - person vomi; 01.04.2020