Search code examples
iphonecocoa-touchcore-datakey-value-observing

Core Data - Watch for changes and register local notifications


I'm relatively new to Core Data and KVC, but I would like some pointers on registering listeners for changes in Core Data objects. Here's the situation:

I have one NSManagedObject called Patient and another called Medication. A Patient may have many Medications, and a Medication has a startOn and endOn dates.

I'd like to somehow listen for changes to the endOn property of all Medication objects. When a change occurs, I would like to schedule a local notification on the iOS device. I've worked with local notifications before, but don't know where to put the code for it in this context.

Do I create the scheduling code in the App Delegate and somehow register the App Delegate to listen for changes in Medication objects? Does this need to be attached to the NSManagedObjectContext?

How is this done? Pointers would be much appreciated!

Thanks!


Solution

  • With Key Value Observing, you need some instance to do the observing. Sometimes that can be the same object that calls -setEndOn: on Medication; sometimes it might have to be something else. Let's assume that your app has a MedicationManager class - of which one instance is created. And, further assume that MedicationManager has an instance method -createMedicationWithName:startOn:endOn: like this:

    - (Medication*) createMedicationWithName:(NSString*)medName startOn:(NSDate*)startDate endOn:(NSDate*)endDate
        {
        //  Create and configure a new instance of the Compound entity 
        Medication *newMedication = (Medication *)[NSEntityDescription insertNewObjectForEntityForName:@"Medication"
                                                    inManagedObjectContext:[self managedObjectContext]];
        [newMedication setName:medName];
        [newMedication setStartOn:startDate];
        [newMedication setEndOn:endDate];
    
        //  Set up KVO
        [newMedication addObserver:self
                        forKeyPath:@"endOn"
                        options:NSKeyValueObservingOptionNew
                        context:nil];
    
        return newCompound;
        }
    
    
    - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
                                                        change:(NSDictionary *)change 
                                                        context:(void *)context
        {
        if ([keyPath isEqualToString:@"endOn"])
            {
            //  ... schedule local notification on the iOS device for (Medication*)object.
            return;
            }
        }
    

    Or something like that.

    Note, when you delete a Medication, then you would want to removeObserver... Also, when launching your app, you would need to establish MedicationManager as observer for existing Medications. I think that this could be as simple as iterating over all Medications and calling addObserver for each. If you have many Medications, then you might want to do this in a more 'lazy' manner (i.e., in -awakeFromFetch).