Фон
Я, как и многие программисты до меня, работаю над приложением, которое имеет дело с деньгами.Я относительно новичок в программировании Какао, но после прочтения руководств я решил, что попытаюсь использовать Core Data, потому что он предоставляет ряд функций, которые мне нужны, и должен уберечь меня от повторного изобретениярулевое колесо.В любом случае, мой вопрос не имеет никакого отношения к тому, должен ли я использовать Core Data: он касается поведения Core Data и самого XCode.
ОБНОВЛЕНИЕ: Iподал в Apple отчет об ошибке и был проинформирован о том, что это дубликат идентификатора проблемы 9405079. Они знают об этой проблеме, но я понятия не имею, когда или если они собираются ее исправить.
Проблема
По какой-то причине, которую я не могу понять, XCode устанавливает ограничения Минимальное значение и Максимальное значение при редактировании свойства Decimal в моей модели управляемого объекта. (я использую десятичные свойства для причин, описанных здесь .)
Предположим, что у меня есть объект Core Data с атрибутом Decimal с именем value
(это просто для иллюстрацииЯ также использовал другие имена атрибутов).Я хочу, чтобы оно имело значение больше 0, но поскольку XCode позволяет мне указывать только минимальное значение (включительно), я устанавливаю Min Value равным 0.01
.К моему большому удивлению, это приводит к предикату проверки SELF >= 0
!Я получаю тот же результат, когда я изменяю минимальное значение: все дробные значения усекаются (минимальное значение задается).Максимальное значение имеет такое же поведение.
В качестве иллюстрации, свойство value
на следующем снимке экрана приведет к предикатам проверки SELF >= 0
и SELF <= 1
.

Как ни странно, но , если я изменю тип этого свойства на Double или Float , предикаты проверки изменятся наSELF >= 0.5
и SELF <= 1.2
, как и ожидалось.Еще более странно, что если я создам свою собственную модель данных в соответствии с Базовым учебным пособием по основным данным , предикаты проверки установлены правильно даже для десятичных свойств .
Оригинальный обходной путь
Поскольку я не могу найти способ исправить эту проблему в редакторе управляемых объектных моделей XCode, я добавил следующий код, обозначенный комментариями begin workaround
и end workaround
, к моемуметод managedObjectModel
делегата приложения (это тот же делегат приложения, который XCode предоставляет по умолчанию при создании нового проекта, использующего базовые данные).Обратите внимание, что я добавляю ограничение, чтобы свойство Transaction
объекта *1059* было больше 0.
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel) return managedObjectModel;
managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
// begin workaround
NSEntityDescription *transactionEntity = [[managedObjectModel entitiesByName] objectForKey:@"Transaction"];
NSAttributeDescription *amountAttribute = [[transactionEntity attributesByName] objectForKey:@"amount"];
[amountAttribute setValidationPredicates:[NSArray arrayWithObject:[NSPredicate predicateWithFormat:@"SELF > 0"]]
withValidationWarnings:[NSArray arrayWithObject:@"amount is not greater than 0"]];
// end workaround
return managedObjectModel;
}
Вопросы
- Это действительно ошибка в том, как XCode генерируетпредикаты проверки для десятичных свойств в моделях управляемых объектов для базовых данных?
- Если да, то есть ли лучший способ обойти это, чем те, которые я описал здесь?
Код Repro
Вы должны быть в состоянии воспроизвести эту проблему с помощью следующего примера кода для класса DebugController
, который выводит ограничения на каждое свойство в модели управляемого объекта на метку.Этот код делает следующие предположения.
- У вас есть делегат приложения с именем
DecimalTest_AppDelegate
- У вашего делегата приложения есть метод
managedObjectContext
- Ваша модель управляемых объектовимеет имя «Кошелек»
Для использования этого кода выполните следующие действия.
- Создание
DebugController
в Интерфейсном Разработчике. - Подключите контроллер
appDelegate
розетка для вашего делегата приложения. - Добавьте оберточную метку (
NSTextField
) к вашему пользовательскому интерфейсу и подключите к ней розетку debugLabel
контроллера. - Добавьте кнопку к вашему интерфейсупользовательский интерфейс и подключите его селектор к действию
updateLabel
контроллера. - Запустите приложение и нажмите кнопку, связанную с действием
updateLabel
.Это выводит ограничения модели управляемого объекта на debugLabel
и должно иллюстрировать поведение, которое я здесь описал.
DebugController.h
#import <Cocoa/Cocoa.h>
// TODO: Replace 'DecimalTest_AppDelegate' with the name of your application delegate
#import "DecimalTest_AppDelegate.h"
@interface DebugController : NSObject {
NSManagedObjectContext *context;
// TODO: Replace 'DecimalTest_AppDelegate' with the name of your application delegate
IBOutlet DecimalTest_AppDelegate *appDelegate;
IBOutlet NSTextField *debugLabel;
}
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
- (IBAction)updateLabel:sender;
@end
DebugController.m
#import "DebugController.h"
@implementation DebugController
- (NSManagedObjectContext *)managedObjectContext
{
if (context == nil)
{
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:[[appDelegate managedObjectContext] persistentStoreCoordinator]];
}
return context;
}
- (IBAction)updateLabel:sender
{
NSString *debugString = @"";
// TODO: Replace 'Wallet' with the name of your managed object model
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Wallet" inManagedObjectContext:[self managedObjectContext]];
NSArray *properties = [entity properties];
for (NSAttributeDescription *attribute in properties)
{
debugString = [debugString stringByAppendingFormat:@"\n%@: \n", [attribute name]];
NSArray *validationPredicates = [attribute validationPredicates];
for (NSPredicate *predicate in validationPredicates)
{
debugString = [debugString stringByAppendingFormat:@"%@\n", [predicate predicateFormat]];
}
}
// NSPredicate *validationPredicate = [validationPredicates objectAtIndex:1];
[debugLabel setStringValue:debugString];
}
@end
Спасибо всем.