Как установить пользовательский атрибут NSManagedObject, который рассчитывается на основе других атрибутов?

Я использую базовую структуру данных для управления объектами. У меня есть объект, который имеет несколько атрибутов десятичных типов. Среди них есть атрибут, который математически вычисляется из других атрибутов. Пример:

@interface Marks :  NSManagedObject  
{  
}

@property (nonatomic, retain) NSDecimalNumber * answerGradeA;  
@property (nonatomic, retain) NSDecimalNumber * answerGradeB;  
@property (nonatomic, retain) NSDecimalNumber * answerGradeC;  
@property (nonatomic, retain) NSDecimalNumber * total;

Здесь я хочу атрибут total = 3xanswerGradeA + 2xanswerGradeB + 1xanswerGradeC.

Если можно сделать так, то как?


person Kundan Pandit    schedule 30.04.2010    source источник


Ответы (3)


Способ Core Data состоит в том, чтобы добавить «итого» в качестве атрибута к модели и пометить его как «переходное». Затем вы предоставляете реализацию в подклассе.

@interface Marks :  NSManagedObject  
{
}
@property (nonatomic, readonly) NSDecimalNumber* total;
@end

@implementation Marks (Calculated)
- (NSDecimalNumber*) total { 
    return (3 * [self valueForKey:@"answerGradeA"]) + (2 * [self valueForKey:@"answerGradeB"]) + [self valueForKey:@"answerGradeC"]; 
}
+ (NSSet *)keyPathsForValuesAffectingTotal
{
    return [NSSet setWithObjects:@"answerGradeA", @"answerGradeB", @"answerGradeC", nil];
}
@end

Это обеспечит правильное кэширование и обновление всего.

person Elise van Looij    schedule 02.05.2010
comment
Поскольку основные данные присваивают значения атрибутам динамически, не нужно ли объявлять эти оставшиеся атрибуты [answerGradeA и т. д.] в этом заголовочном файле вместе с итогом, чтобы этот атрибут знал, каково значение ключа answerGradeA во время вычислений. - person Kundan Pandit; 03.05.2010
comment
Нет, к счастью, компилятор достаточно умен, чтобы понять это самостоятельно. Более того, каждая строчка, написанная программистом, является потенциальным источником проблем и ошибок: «меньше значит больше» так же верно в программировании, как и в жизни. Позвольте Core Data делать свое дело и подталкивайте его в правильном направлении только тогда, когда это необходимо. - person Elise van Looij; 25.05.2010

Почему бы не сделать его категорией и не скомпилировать в отдельный файл? (Строго говоря, total не должен быть частью CoreData.)

@interface Marks (Calculated)
@property (nonatomic, readonly) NSDecimalNumber* total;
@end

@implementation Marks (Calculated)
- (NSDecimalNumber*) total { 
  return whatEverYouLike; 
}
@end
person Jens    schedule 30.04.2010
comment
+1: Использование категорий идеально, потому что, если вы измените модель данных и создадите новый заголовок объекта и файлы реализации, ваша категория останется отдельной и неповрежденной. - person Alex Reynolds; 01.05.2010
comment
Почему Total не должна быть частью модели Core Data? @Kundan определяет здесь total как сумму трех конкретных свойств — трудно понять, почему Маркс не должен нести ответственность за обеспечение реализации total, если только @Kundan не имеет доступа к исходному коду. - person Elise van Looij; 02.05.2010
comment
Это зависит от того, что вы собираетесь делать с тоталом. Если вы хотите продолжить обработку, запрос, отмену... "всего", то ваш подход с переходными свойствами работает нормально (даже если переходные свойства могут быть сложными). Если бы нужно было просто добавить 3 числа, я бы, наверное, не стал менять модель для этой цели. - person Jens; 02.05.2010

Я хочу опубликовать небольшую модификацию ответа Луджи.

@interface Marks :  NSManagedObject  
{
}
@property (nonatomic, retain) NSDecimalNumber * answerGradeA;
@property (nonatomic, retain) NSDecimalNumber * answerGradeB;
@property (nonatomic, retain) NSDecimalNumber * answerGradeC;
@property (nonatomic, readonly) NSDecimalNumber* total;
@end

@implementation Marks (Calculated)
- (NSDecimalNumber*) total { 
return (3 * [self valueForKey:@"answerGradeA"]) + (2 * [self valueForKey:@"answerGradeB"]) + [self valueForKey:@"answerGradeC"]; 
}
+ (NSSet *)keyPathsForValuesAffectingTotal
{
return [NSSet setWithObjects:@"answerGradeA", @"answerGradeB", @"answerGradeC", nil];
}
@end
person Kundan Pandit    schedule 06.05.2010