Еще раз про валидацию данных в Core Data

Создадим новый проект:


Сделаем модель данных:

Простейшее правило валидации заключается в том чтобы сделать атрибут обязательным для заполнения и убрать для него значение по умолчанию:

Managed object context может быть создан по необходимости при первом вызове:

MyDocument.h

#import <Cocoa/Cocoa.h>
@interface MyDocument : NSPersistentDocument {
NSManagedObject *customer;
}
- (NSManagedObject *)customer;
- (void)setCustomer:(NSManagedObject *)aCustomer;
@end


MyDocument.m

#import “Document.h”
@implementation Document
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (id)initWithType:(NSString *)type error:(NSError **)error
{
self = [super initWithType:type error:error];
if (self != nil) {
NSManagedObjectContext *managedObjectContext = [self
managedObjectContext];
[self setCustomer:[NSEntityDescription
insertNewObjectForEntity-ForName:@”Customer
inManagedObjectContext:managedObjectContext]];
}
return self;
}
- (NSString *)windowNibName
{
return @”Document;
}
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
[super windowControllerDidLoadNib:aController];
}
+ (BOOL)autosavesInPlace
{
return NO; // see comment about testing
}
#pragma mark - Core Data stack
- (NSManagedObject *)customer
{
if (customer != nil)
{
return customer;
}
NSManagedObjectContext *moc = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSError *fetchError = nil;
NSArray *fetchResults;
@try
{
NSEntityDescription *entity = [NSEntityDescription
entityForName:@”Customer
inManagedObjectContext:moc];
[fetchRequest setEntity:entity];
fetchResults = [moc executeFetchRequest:fetchRequest
error:&fetchError];
} @finally
{
// for non-ARC projects, this would be [fetchRequest release];
}
if ((fetchResults != nil) && ([fetchResults count] == 1) && (fetchError
== nil))
{
[self setCustomer:[fetchResults objectAtIndex:0]];
return customer;
}
if (fetchError != nil){
[self presentError:fetchError];
}
else {
// your own error message
}
return nil;
}
- (void)setCustomer:(NSManagedObject *)aCustomer
{
if (customer != aCustomer)
{
customer = aCustomer;
}
}
@end


Создадим nib файл, добавим текстовые поля и object controller, который надо забиндить на managedObjectContext в File’s Owner.

Соедините биндинги из Customer controller с полями данных.

Надо выбрать поле данных, перейти в инспектор биндингов, и в секции Value привязать к Customer контроллеру. Controller Key надо установить в значение selection. Для Model Key Path нужно ввести наименование атрибута в модели данных.

При попытке сохранить неправильные данные будет появляться сообщение об ошибке:

Если ошибок несколько, то будет появляться общее сообщение:

Основой NSKeyValueCoding являются методы:


- (id)valueForKey:(NSString *)key
- (void)setValue:(id)value forKey:(NSString *)key

Key-value валидация это API построенный на тех же концепциях, который позволяет валидировать значения свойств. Основной методы выполняющий валидацию:


- (BOOL)validateValue:(id *)ioValue forKey:(NSString *)key
error:(NSError **)outError

Не нужно перекрывать метод validateValue:forKey:error. Он реализован в классе NSManagedObject. Если вы вызываете метод validateValue например для ключа price, то он ищет метод для валидации данного ключа, который будет следующим:


- (BOOL)validatePrice:(id *)ioValue error:(NSError **)outError

Вам не нужно вызывать этот метод самому.

NSError является прямым наследником NSObject. Основные свойства:
  • code - NSInteger идентифицирующий ошибку;
  • domain - NSString идентифицирующий область из которой вышла данная ошибка: NSMachErrorDomainNSPOSIXErrorDomainNSOSStatusErrorDomainNSCocoaErrorDomain, com.yourorganization.yourapp.ErrorDomain
  • userInfo - NSDictionary с деталями проблемы. Словарь содержит локализованные строки для следующих ключей: NSLocalizedDescriptionKey, NSErrorFailingURLStringKey, NSFilePathErrorKey, NSStringEncodingErrorKey, NSUnderlyingErrorKey, NSURLErrorKey, NSLocalizedFailureReasonErrorKey, NSLocalizedRecoverySuggestionErrorKey, NSLocalizedRecoveryOptionsErrorKey, NSRecoveryAttempterErrorKey, NSHelpAnchorErrorKey, NSURLErrorFailingURLErrorKey, NSURLErrorFailingURLStringErrorKey, NSURLErrorFailingURLPeerTrustErrorKey. Если нужно ключа нет, то используется ключ NSUnderlyingErrorKey.

NSManagedObject следующие методы которые можно перекрыть:

- (BOOL)validateForInsert:(NSError **)error
- (BOOL)validateForDelete:(NSError **)error
- (BOOL)validateForUpdate:(NSError **)error

Пример:

- (BOOL)validateForUpdate:(NSError **)error {
[super validateForUpdate: error];
// your quality edit
}