Получить дату модификации для NSManagedObject в Core Data?

Помимо добавления свойства NSDate к каждому объекту в моем хранилище основных данных, существует ли программный способ получить дату модификации для любого объекта?


person Jason    schedule 28.04.2011    source источник


Ответы (7)


Нет, вы должны добавить дату и управлять ею самостоятельно. Вы можете использовать переопределение -willSave в своем управляемом объекте, чтобы обновить отметку времени, но прочитайте документацию API для NSManagedObject на -willSave, чтобы узнать, как выполнить обновление, не вызывая цикла willSave (в документах даже говорится о случае обновления отметки времени). В документах также упоминается использование NSManagedObjectContextWillSaveNotification, но это может вызвать больше проблем с настройкой, чем простая проверка, чтобы не устанавливать отметку времени слишком быстро.

person Kendall Helmstetter Gelner    schedule 28.04.2011
comment
Apple дает примеры того, как это сделать. Прочтите о -willSave: developer.apple.com/library/mac/#documentation/Cocoa/Reference/ - person Michael Ozeryansky; 21.09.2012
comment
Вот обновленная ссылка: developer.apple.com/documentation/coredata/nsmanagedobject/ - person blwinters; 16.01.2018

Я лично проверяю, был ли изменен updatedAt, и если да, то больше его не трогаю. Таким образом я прерываю цикл willSave.

- (void)awakeFromInsert {
    [super awakeFromInsert];

    self.primitiveUpdatedAt = [NSDate date];
}

- (void)willSave {
    [super willSave];

    if(![self isDeleted] && self.changedValues[@"updatedAt"] == nil) {
        self.updatedAt = [NSDate date];
    }
}
person Ben Affleck    schedule 30.10.2015

Обратите внимание, что это решение предполагает, что у нас есть свойство с именем dateUpated в модели.

Вместо того, чтобы обрабатывать это на отдельных объектах. Я бы справился с этим через уведомление. Документация Apple также предлагает этот путь.

1. Зарегистрируйтесь для получения уведомления NSManagedObjectContextWillSaveNotification.

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(willSaveContext:)         
                                             name:NSManagedObjectContextWillSaveNotification 
                                           object:nil];

2 Установите свойство для updatedDate в методе наблюдателя для каждого обновленного объекта.

- (void)willSaveContext:(NSNotification *)notification{

    NSManagedObjectContext *context = [notification object];
    NSSet *updatedObject = [context updatedObjects];

    for (NSManagedObject *managedObject in [updatedObject allObjects]) {
        if ([[managedObject.entity propertiesByName] objectForKey:@"dateUpdated"]) {
            [managedObject setValue:[NSDate date] forKey:@"dateUpdated"];
        }

    }

}
person MadNik    schedule 04.03.2015

На WWDC19 об этом было объявлено Производные атрибуты.

Атрибут updated, подобный этому, автоматически обновляется Core Data:

Снимок экрана основного производного атрибута

Примечание. Это может привести к созданию недопустимой модели сопоставления.

person Diogo T    schedule 11.06.2020
comment
Хорошие новости! Большое спасибо! - person Nikaaner; 25.03.2021

Я нашел этот вопрос/ответ полезным для начала настройки атрибута даты, измененной в Core Data. В процессе я пришел к паре советов, которые также могут помочь:

(Совет 1: избегайте рекурсии willSave)

  • Еще один способ избежать цикла willSave — написать специальную процедуру для сохранения контекста, которая выполняет итерацию по своим updateObjects в поисках тех, у которых есть свойство dateModified, и устанавливает его. Выполните фактические вызовы commitEditing и save после этого цикла. Не беспокойтесь о willSave вообще.

(Совет 2: живое обновление — но не работает с отменой)

  • Если вам нужно оперативное обновление для отображения даты, измененной для пользователя в таблице, вы также можете установить dateModified в вашем переключателе (или что-то еще) для столбца с измененной датой в вашем методе делегата objectValueForTableColumn (willDisplayCell для iOS).

  • Там проверьте, обновлен ли объект для этой строки, и если да, установите dateModified. Сомневаюсь, что if (obj isUpdated) чек стоит очень дорого. Но обязательно делайте это только для соответствующего столбца, чтобы не повторять без необходимости.

  • Верните любое строковое представление, которое вы используете для столбца. Чтобы избежать очевидных несоответствий между временем фактического изменения и установленной датой, покажите только дату, а не время.

  • Это приведет к обновлению dateModified всякий раз, когда пользователь делает выбор таблицы, а также когда таблица перезагружается. Что не идеально: если пользователь изменяет атрибут, не представленный в таблице, столбец не будет обновляться, пока он не сделает выбор. Но это достаточно быстро и намного проще, чем реализация обширной схемы KVO.

  • (Вы все равно захотите установить дату в процедуре сохранения, чтобы уловить изменения, невидимые для таблицы.)

  • УСЛОЖНЕНИЕ ОТМЕНЫ: К сожалению, диспетчер отмены будет рассматривать изменение метода делегата таблицы на dateModifed как отдельное событие. Последующий вызов undo просто отменяет последнее изменение в dateModified — снова и снова. Я попытался обойти это, добавив средство отслеживания и проверку непустого словаря измененных значений, чтобы убедиться, что dateModified был установлен только после предварительного сохранения. Это работало для отмены удалений, но не для обычных правок. Таким образом, нет быстрого способа выполнить живое обновление предварительного сохранения dateModified.

person Wienke    schedule 18.12.2011
comment
Совет 0: Apple рассказывает, как избежать рекурсии willSave в документации. developer.apple.com /library/mac/#documentation/Какао/Справочник/ - person Michael Ozeryansky; 21.09.2012

Если кому-то нужен простой способ сделать это в Swift: я написал запись в блоге о простом классе UpdateListener для обновления всех свойств updateDate и insertDate. Вы можете найти весь класс в этой сути. Все, что вам нужно сделать, это вызвать UpdateListener.setupSharedInstance() в методе application(:didFinishLaunchingWithOptions:) вашего делегата приложения.

person Rugen Heidbuchel    schedule 03.09.2015

Быстрая версия ответа Бена Аффлека

public override func willSave() {
    super.willSave()
        
    if !isDeleted, changedValues()["updatedAt"] == nil {
        self.setValue(Date(), forKey: "updatedAt")
    }
}
person lewis    schedule 05.04.2021