Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSManagedObject timeStamp update

I want to track changes of NSManagedObject properties, in order to keep NSData *lastUpdate property "up to date"

There are several approaches to get Notified when NSManagedObject changes its properties

I. First is to override the setter Methods of all properties you want to track. Which is quite complicated in NSManaged object - check it here

II. Second could be a good one. You can just override "didChangeValueForKey" method That is called on every property change.

-(void)didChangeValueForKey:(NSString *)key{
    [super didChangeValueForKey:key];
    NSLog(@"Value for key:%@ has changed", key);
}

Unfortunately we should not override this method due to the documentation that says...:

"You must not override this method."

III. Key-value-observing leads us back to IInd approach, with overriding "didChangeValueForKey".

upd. IV. I tried to override -willSave method

-(void)willSave{
   NSArray *observedKeys = @[@"name", @"imageType"];
   NSDictionary * changesALL = self.changedValues;
   for (id key in changesALL){
       if ([observedKeys containsObject:key]){
           self.lastUpdate = [NSDate date];
           NSLog(@"updated For key: %@", key);
        }
    }
}

This led infinitive loop, which is described in documentation. (altho the right approach is described here, so I've answered this question already)

If you want to update a persistent property value, you should typically test for equality >of any new value with the existing value before making a change. If you change property >values using standard accessor methods, Core Data will observe the resultant change >notification and so invoke willSave again before saving the object’s managed object >context. If you continue to modify a value in willSave, willSave will continue to be called >until your program crashes.

For example, if you set a last-modified timestamp, you should check whether either you >previously set it in the same save operation, or that the existing timestamp is not less >than a small delta from the current time. Typically it’s better to calculate the timestamp >once for all the objects being saved (for example, in response to an >NSManagedObjectContextWillSaveNotification).

like image 728
KIO Avatar asked Mar 20 '23 20:03

KIO


2 Answers

A suitable solution for your use case to override the willSave method and use it to set the new lastUpdated value. This method is called automatically on dirty objects before they are saved into the context.


If you need to verify what is dirty you can use the contents of the changedValues property.

like image 50
Wain Avatar answered Mar 31 '23 13:03

Wain


So after all I figured out that the best solution to track changes of Managed Object is to register for NSManagedObjectContextWillSaveNotification instead, and set the timestamp on all updated and inserted objects in the managed object context. The registered method could look like this:

-(void)contextWillSave:(NSNotification *)notify
{
NSManagedObjectContext *context = [notify object];
NSDate *dateOfTheLastModification = [NSDate date];
for (NSManagedObject *obj in [context insertedObjects]) {
    [obj setValue:dateOfTheLastModification forKey:@"lastUpdate"];
}
for (NSManagedObject *obj in [context updatedObjects]) {
    [obj setValue:dateOfTheLastModification forKey:@"lastUpdate"];
}
}

This assumes that all your entities have a lastModifiedDate attribute, otherwise you have to check the class of the objects.

like image 29
KIO Avatar answered Mar 31 '23 13:03

KIO