开发者

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 i开发者_如何学Gon 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!


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


You will have to register observers when objects are fetched from the store the first time as well as when they are created. Instead of having to loop through all of the entries when you first fetch (which is error prone especially on the iPhone when unmodified fetched objects can be faulted when not retained) just use the awakeFromFetch and awakeFromInsert messages.

Also, in the example code below you can also keep up with the Patient's aggregate information like the soonest startOn and the soonest endOn by making transient properties on the Patient which store this information. The following code observes changes to the endOn in the Medication and offers you the ability to update the Patient's aforementioned transient "soonest endOn" or "soonest startOn"

- (void)addMyObservers
{
    registeredObservers_ = YES;
    [self addObserver:self forKeyPath:@"endOn" options:NSKeyValueObservingOptionNew context:nil]; 
}

- (void)awakeFromInsert 
{
    // called when you create this object
    [super awakeFromInsert];
    [self addMyObservers];
}

- (void)awakeFromFetch
{
    // called when you fetch this old object from the store
    [super awakeFromFetch];
    [self addMyObservers];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if([keyPath isEqualToString:@"endOn"]) 
    {
        id newValue = [change objectForKey:NSKeyValueChangeNewKey];
        // someone changed endOn so do something with this "newValue"
        // check to see if the Patient needs the transient property for the soonest medication updated
        // update any local notification schedule 
    }
}

// this is only required if you want to update the Patient's transient property for the soonest endOn or 
- (void)setPatient:(Patient *)patient
{
    [self willChangeValueForKey:@"patient"];
    [self setPrimitivePatient:patient];
    [self didChangeValueForKey:@"patient"];

    // check to see if the Patient needs the transient property for the soonest medication updated
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜