3

I have a subclassed NSManagedObject that conforms to the MKAnnotation protocol and it has NSNumber properties for latitude and longitude.

When I change any coordinates myself, I use setCoordinate: and update the latitude and longitude properties inside the implementation of setCoordinate:. Using this method, the map view updates the annotations. However, when I merge changes with another NSManagedObjectContext via mergeChangesFromContextDidSaveNotification:, setCoordinate: is not used because the latitude and longitude properties are explicitly changed. This prevents any KVO notifications going out about the coordinate changing.

I have tried to get the map view to realize the coordinate depends on the latitude and longitude properties with this code:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];

    if ([@"coordinate" isEqualToString:key]) {
        NSSet *affectingKeys = [NSSet setWithObjects:@"latitude", @"longitude", nil];
        keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKeys];
    }

    return keyPaths;
}

However that code produces this crash:

Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer for the key path "coordinate" from because it is not registered as an observer.'

Any ideas on how to prevent that crash or alternative methods to get the coordinate KVO notification sent out when the latitude or longitude is changed? Thanks for taking a look.

Devin McKaskle
  • 802
  • 1
  • 8
  • 15

2 Answers2

1

I fixed this by changing setCoordinate: so that it uses the primitive accessors that are automatically generated by Core Data to set the latitude and longitude properties.

I suspect that because my keyPathsForValuesAffectingValueForKey: made the coordinate key dependent on both the latitude and longitude keys, the MKMapView was getting confused when setCoordinate: used the public accessors instead of the primitive accessors.

When the public accessor methods were used to set the latitude and longitude, any object observing the coordinate key path observed three separate changes (for the key paths coordinate, latitude, and longitude) when there was only one change (coordinate) that should be observed, which confused the map view.

Devin McKaskle
  • 802
  • 1
  • 8
  • 15
  • Also I'd like to note that, because `coordinate` is not a modeled property in my `NSManagedObject`, I had to return `NO` for `+ (BOOL)contextShouldIgnoreUnmodeledPropertyChanges`. Without that, the `NSManagedObjectContext` wasn't saving the changes since I am using primitive accessors. – Devin McKaskle Feb 22 '12 at 23:17
0

It's a little overhead, but you could observe the latitude and longitude params (resp. override their setters), and force-set the coordinate (with setCoordinate:) when the change.

  • I don't mind the overhead, but my `setCoordinate:` method uses `setLatitude:` and `setLongitude:`, so it would make an infinite loop. – Devin McKaskle Feb 21 '12 at 19:53