Уведомление NSManagedObjectContextObjectsDidChange отправляется только тогда, когда к измененному управляемому объекту обращались ранее.Зачем? - PullRequest
0 голосов
/ 21 мая 2018

(см. Обновления ниже для получения более подробной информации.)

это странная проблема.Я не могу опубликовать все в своем классе (это слишком много), поэтому я попытаюсь охватить основные части:

У меня есть контроллер представления с viewDidLoad() методом:

class MyClass {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()        

        // mainViewContext is the viewContext passed by AppDelegate's persistentContainer
        NotificationCenter.default.addObserver(self, selector: #selector(test(notif:)), name: Notification.Name.NSManagedObjectContextObjectsDidChange, object: mainViewContext)
    }
    ...
    @objc func test(notif: Notification) {
        print("I got called")
    }
    ...

Итак, я добавил наблюдателя, чтобы узнать, был ли изменен объект CoreData.Однако это уведомление не публикуется всегда.Когда я делаю это (например, в viewDidLoad() сразу после добавления наблюдателя):

self.appDelegate.persistentContainer.performBackgroundTask({ (privateContext) in
    // FileBrowserElement is a managed object I created
    let folder = privateContext.object(with: App.rootFolderObjectID) as! FileBrowserElement
    // Random number so that the name really changes everytime (so that there is something to change when saving)
    folder.name = "newFolderName" + String(Int.random(between: 0, and: 90000))

    do {
        try privateContext.save()
    } catch let error as NSError {
        print("Error: " + error.debugDescription)
    }
})

это работает.test(notif:) вызывается.Но теперь я заменяю его следующим:

self.appDelegate.persistentContainer.performBackgroundTask({ 
(privateContext) in
    // Just another type of managed object I have.
    let folder = privateContext.object(with: App.templateRackObjectID) as! Rack
    folder.name = "newFolderName" + String(Int.random(between: 0, and: 90000))

    do {
        try privateContext.save()
    } catch let error as NSError {
        print("Error: " + error.debugDescription)
    }
})

И он больше не работает.test(notif:) не вызывается.Я понятия не имею, почему это так.Я буквально изменил только изменяемый объект.

(я установил persistentContainer.viewContext.automaticallyMergesChangesFromParent = true в AppDelegate)

Размещается ли уведомление только для некоторых типов управляемых объектов?Я что-то скучаю?Я не знаю, как начать отлаживать это.Я пытался часами.Это очень странно.

Есть мысли?Дайте мне знать, если вам нужна дополнительная информация.Как я уже сказал, я не знаю, что важно для этого вопроса.Весь класс был бы слишком большим, чтобы публиковать здесь.

ОБНОВЛЕНИЕ: Я попытался воссоздать эту проблему с фиктивным проектом.Странно, это не отправка уведомления ни с одним из управляемых объектов.Я загрузил его в github: https://github.com/d3mueller/NotificationTestProject

Может, я там что-то не так сделал, чего не вижу?

ОБНОВЛЕНИЕ 2 (что-то нашел. Я обновилрепо) Итак, это невероятно странно.У меня было подозрение, что оно оказалось правдоподобным (наверное).

Кажется, что уведомление отправляется только тогда, когда вы ранее загрузили тот же управляемый объект, который хотите изменить и получить доступ к его атрибуту.Я добавил это прямо перед запуском performBackgroundTask:

// As a class attribute, I added `private var rack: Rack!`. Then this is in `viewDidLoad`, right before the background task
   rack = mainViewContext.object(with: App.templateRackObjectID) as! Rack
            _ = rack.name

Теперь все работает.Но почему?Это странно.Почему я должен получить к нему доступ раньше?Уведомление всегда должно быть отправлено.Есть мысли по этому поводу?Я добавил это в фиктивный проект на Github, если вы хотите попробовать его.

Буду очень признателен за любую помощь в этом:)

1 Ответ

0 голосов
/ 14 марта 2019

Наткнулся на это и сегодня.Контекст не сохраняет объекты и, следовательно, не «обновляет» ваши объекты.Я обнаружил, что установка retainsRegisteredObjects на true заставит контекст начать отправку ожидаемых уведомлений.

...