简体   繁体   中英

How to implement a read only attribute in a Core Data app

I'm developing a Core Data app that uses a model object called Location. The user can enter locations and provide their latitude and longitude in decimal format. I use plain NSTextFields for this. As a feedback to the user, also their degrees/minutes/seconds counterparts are shown (using a label). The logic for transforming from decimal format to degrees etc. is implemented with the Location model object, which is a subclass of NSManagedObject .

Ideally I want to implement these as read-only attributes and have them tied in some way to their decimal counterpart, so that when the user changes the decimal representation, the degrees/minutes/seconds representation gets updated as well.

I've tried the following:

  • Set the controller as an NSTextFieldDelegate to intercept edits but this only works if the user actually edits the fields. This fails when the user accepts 0 as defaults for both latitude and longitude, which is actually a valid location.
  • I've looked at transient attributes for Core Data but found the documentation on this point not very helpful, although they might be the answer for this...

Any ideas on how to approach this?

EDIT:

As suggested by Francis McGrew, I implemented the following class method for Location :

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

    if ([key isEqualToString:@"latitudeToDegrees"] || [key isEqualToString:@"longitudeToDegrees"]) {
        result = [result setByAddingObjectsFromSet:[NSSet setWithObjects: @"latitude", @"longitude", nil]];
    }
    return result;
}

Slightly different from his answer, as the DMS is just one attribute represented as a formatted String, calculated by Location . I then added bindings in the UI to latitudeToDegrees and longitudeToDegrees and ...boom!.., a nicely updated UI.

If someone could explain transient properties to me I'd love to hear it as well.

Since DMS is easily calculated from the latitude and longitude, there's no real reason to store those values as attributes in your model. I would just write methods that calculate and return the current degrees, minutes and seconds based on the saved latitude and longitude attributes.

Then, to have Core Data automatically notify obervers of changes, you would implement the following method in your Location class:

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

    if ([key isEqualToString:@"degrees"] ||
        [key isEqualToString:@"minutes"] ||
        [key isEqualToString:@"seconds"]) {

        result = [result setByAddingObjectsFromSet:[NSSet setWithObjects:
            @"latitude", @"longitude", nil]];
    }
    return result;

}

This tells Core Data that the "transient" degrees, minutes and seconds are dependent on your latitude and longitude attributes. Assuming you're using bindings, your user interface should update automatically. To prevent the user from editing the text fields, just set their behavior to "Selectable" or "None" in your XIB. (In XCode 3 I think you just uncheck the "Editable" box)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM