Question

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).

Was it helpful?

Solution 2

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.

OTHER TIPS

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.

To avoid the infinite loop, try this magic:

- (void)willSave{
    if(![self.changedValues objectForKey:@"localModificationDate"]){
        self.localModificationDate = [NSDate date];
    }
    else{
        [super willSave];
    }
}

Once the modification date has been set it won't set it again for the current save. There is a side affect that if the save fails and you save successfully again, I reckon the date will be the from the previous save attempt.

This is fine if you are saving the context after every edit, but the usual design of core data is to only save either at app suspend or after a long time. So it's likely the lastUpdate will be needed for something before then and it won't have the new value yet.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top