Методы акцессоры управляемых объектов Core Data в среде Cocoa, Mac OS, iOS

Cocoa

В данном разделе объясняется, почему вы можете реализовать собственные методы доступа для управляемых объектов, и, как реализовать их атрибуты и связи. Здесь также показывается, как реализовать примитивные методы доступа.

Обзор

В Mac OS X 10.5, Core Data динамически генерирует эффективный общедоступные и примитивные get и set методы доступа к атрибутам и методы доступа для отношений управляемых классов объектов. Как правило, таким образом, нет необходимости писать методы доступа к свойствам, которые определены в сущности соответствующего управляемого объекта модели управляемого объекта, хотя вы можете использовать Objective-C декларирование свойств для объявления свойств, чтобы подавить предупреждений компилятора. Чтобы получить наилучшую производительность и воспользоваться проверкой типов , используйте методы доступа непосредственно, хотя они также совместимы для кодирования ключ-значение (KVC), чтобы при необходимости можно использовать стандартные методы кодирования ключ-значение, такие как valueForKey. Вам нужно написать свои методы доступа, если вы используете временные свойства для поддержки нестандартных типов данных, или если вы используете скалярные переменные экземпляра представляющие собой атрибуты.

Пользовательские реализации

Реализация методов доступа написанная для подклассов NSManagedObject, как правило, отличается от той, которую пишут для других классов.

  • Если вы не предоставите пользовательские переменные, например, извлекающие значения свойств и сохраняющие значения во внутреннее хранилище используя примитивные методы доступа.
  • Вы должны убедиться, что вы вызываете соответствующий доступ и уведомление об изменении методами (willAccessValueForKey:, didAccessValueForKey:, willChangeValueForKey:, didChangeValueForKey:, willChangeValueForKey:withSetMutation:usingObjects: и didChangeValueForKey:withSetMutation:usingObjects:).
  • В методах доступа к свойствам, которые не определены в сущности модели, вы можете включить автоматическое уведомление изменения или вызов соответствующих методов уведомления об изменении.

Вы можете использовать инструмент моделирования данных Xcode для генерации кода для методов доступа к любому моделируемому свойству.

Модель доступа кодирования Ключ-значение

Модель доступа кодирования ключ-значение используется для управляемых объектов в значительной степени так же как, и для подкласса NSObject. Разница в том, что, если после проверки нормальной резолюции valueForKey: возбуждал исключение для несвязанных ключевых пар, механизм кодирования ключ-значение NSManagedObject проверяет ключ моделируемого свойства. Если ключ соответствует свойству сущности, механизм ищет сначала метод доступа формы primitiveKey, и если не найдено, то ищется значение ключа внутреннего хранилища управляемого объекта. Если не находит, NSManagedObject генерирует исключение, несвязанных ключей (как valueForKey:).

Динамически генерируемые методы акцессоров

По умолчанию, Core Data динамически создает эффективные общедоступные и примитивные get и set методы доступа к моделируемым свойствам (атрибутам и связям) управляемых классов объектов. Это включает в себя кодирование ключ-значение изменяемым прокси методов таких, как add<Key>Object:, и remove<Key>s:, как указано в документации для mutableSetValueForKey:-управляемые объекты эффективно изменяемые прокси для всех отношений ко-многим.

Примечание: Если вы решили реализовать собственные средства доступа, динамически генерируемые методы никогда не заменят Вашего собственного кода.

Например, если есть сущность с атрибутами firstName, Core Data автоматически генерирует firstName, setFirstName:, primitiveFirstName и setPrimitiveFirstName:. Core Data делает это даже для сущностей представленных ​​NSManagedObject. Для подавления предупреждений компилятора при вызове этих методов, вы должны использовать Objective-C 2.0 объявления свойств функций.

Методы доступа к свойствам основных данных создается по умолчанию (nonatomic, retain)-это рекомендуемая конфигурация. Методы nonatomic потому что не атомарный доступ является более эффективными, чем атомарнный, и в целом не представляется возможным обеспечить безопасность потока в приложении Core Data на уровне методов доступа.

Объявление

Вы можете использовать Objective-C 2.0 свойства для объявления свойств управляемого объекта класса, вы обычно это делаете, чтобы использовать акцессоры Core Data по умолчанию, без генерации предупреждений компилятора. Самый простой способ получения объявлений заключается в выборе отношений в инструменте моделирования Xcode и выберите Design > Data Model > Copy Obj-C 2.0 Method Declarations to Clipboard., а затем измените код, если это необходимо.

Вы объявляете атрибуты и связи, как если бы это были свойства для любого другого объекта, как показано в следующем примере. При объявлении отношений ко-многим, тип свойства должен быть NSSet*. (Значение, возвращаемое методом доступа не является KVO-совместимым прокси-изменяемым.)

@interface Employee : NSManagedObject
{ 

}
@property(nonatomic, retain) NSString* firstName, lastName;
@property(nonatomic, retain) Department* department;
@property(nonatomic, retain) Employee* manager;
@property(nonatomic, retain) NSSet* directReports;
@end

Если вы не используете пользовательский класс для подавления предупреждений компилятора можно объявить свойства в категории NSManagedObject:

@interface NSManagedObject (EmployeeAccessors)

@property(nonatomic, retain) NSString* firstName, lastName;
@property(nonatomic, retain) Department* department;
@property(nonatomic, retain) Employee* manager;
@property(nonatomic, retain) NSSet* directReports;
@end

Вы можете использовать те же методы для подавления предупреждений компилятора для автоматически генерируемых отношений ко многим мутаторам методов, например:

@interface Employee (DirectReportsAccessors)

- (void)addDirectReportsObject:(Employee *)value;
- (void)removeDirectReportsObject:(Employee *)value;
- (void)addDirectReports:(NSSet *)value;
- (void)removeDirectReports:(NSSet *)value;

@end

Обычно вы сохраняете атрибуты, хотя и сохраняете инкапсуляцию, где атрибут класса имеет изменяемый подкласс и реализует протокол NSCopying Вы также можете использовать copy, например:

@property(nonatomic, copy) NSString* firstName, lastName;

Реализация

Вы можете указать реализацию, используя ключевое слово @dynamic, как показано в следующем примере, поскольку @dynamic создается по умолчанию, нет необходимости делать это:

@dynamic firstName, lastName;
@dynamic department, manager;
@dynamic directReports;

Тут должно быть правило, не нужно чтобы вы обеспечивали свою собственную реализацию этих методов, если вы хотите поддерживать скалярные значения. Методы, которые генерирует Core Data во время выполнения более эффективны, чем те, которые вы можете реализовать сами.

Наследование

Если у вас есть два подкласса NSManagedObject где родительский класс реализует динамическое свойство и его подкласс (внук NSManagedObject) переопределяет методы свойств, эти переопределения не могут вызвать super.

@interface Parent : NSManagedObject
@property(nonatomic, retain) NSString* parentString;
@end

@implementation Parent
@dynamic parentString;
@end

@interface Child : Parent
@end

@implementation Child
- (NSString *)parentString
{
    // Здесь возбуждается исключение "selector not found"
    return parentString.foo;
}
@end

Пользовательские атрибуты и методы акцессоров отношений к-одному

Важно, Настоятельно рекомендуется использовать динамические свойства (то есть свойства, для осуществления которых вы укажете @dynamic), вместо того, чтобы создавать собственные реализации для стандартных или примитивных методов доступа.

Листинг 1 Реализация пользовательского управляемого объекта класса, иллюстрирующий методы аксессоров атрибутов.

@interface Department : NSManagedObject
{

}
@property(nonatomic, retain) NSString *name;
@end

 
@interface Department (PrimitiveAccessors)
- (NSString *)primitiveName;
- (void)setPrimitiveName:(NSString *)newName;
@end

 

@implementation Department

@dynamic name;

- (NSString *)name
{
    [self willAccessValueForKey:@"name"];
    NSString *myName = [self primitiveName];
    [self didAccessValueForKey:@"name"];
    return myName;
}

- (void)setName:(NSString *)newName
{
    [self willChangeValueForKey:@"name"];
    [self setPrimitiveName:newName];
    [self didChangeValueForKey:@"name"];
}
@end

Реализация по умолчанию не копирует значения атрибутов. Если значение атрибута может быть изменяемым и поддерживает NSCopying протокол (как и в случае с NSString, например), вы можете скопировать значение в пользовательском аксессоре, чтобы помочь сохранить инкапсуляцию (например, в случае, когда экземпляр является NSMutableString передается в качестве значения). Это показано в листинге 2. Отметим также, что (для иллюстрации) в этом примере методы доступа не реализованы, так как они не реализованы, Core Data будет генерировать их автоматически.

Листинг 2 Реализация пользовательского класса управляемого объекта, иллюстрирующий копирование в сеттере.

@interface Department : NSManagedObject
{

}
@property(nonatomic, copy) NSString *name;
@end

@implementation Department

@dynamic name;

- (void)setName:(NSString *)newName
{
    [self willChangeValueForKey:@"name"];
    
    // NSString поддерживает NSCopying, для копирования атрибута name
    
    NSString *newNameCopy = [newName copy];
    [self setPrimitiveName:newNameCopy];
    [newNameCopy release];
    [self didChangeValueForKey:@"name"];
}
@end

Если Вы хотите представлять атрибут с помощью скалярного типа (например, NSInteger или CGFloat), или как одну из структур поддерживаемой NSKeyValueCoding (NSRect, NSPoint, NSSize, NSRange), то вы должны реализовать методы доступа, как показано в листинге 3.

Листинг 3 Реализация пользовательского класса управляемого объекта, иллюстрирующий скалярные значения атрибута.

@interface Circle : NSManagedObject
{
    CGFloat radius;
}
@property CGFloat radius;
@end

@implementation Circle

- (CGFloat)radius
{
    [self willAccessValueForKey:@"radius"];
    float f = radius;
    [self didAccessValueForKey:@"radius"];
    return f;
}

- (void)setRadius:(CGFloat)newRadius
{
    [self willChangeValueForKey:@"radius"];
    radius = newRadius;
    [self didChangeValueForKey:@"radius"];
}
@end

Пользовательские атрибуты и методы акцессоров отношений ко-многим

Важно, Настоятельно рекомендуется использовать динамические свойства (то есть свойства, для осуществления которых вы укажете @dynamic), вместо того, чтобы создавать собственные реализации для стандартных или примитивных методов доступа.

Обычно доступ к отношениям ко-многим осйществляется с использованием mutableSetValueForKey:, который возвращает прокси-объект, как изменяемое отношение и посылает соответствующий ключ-значение уведомление наблюдения для Вас. Тут должно быть правило, что весьма мало оснований для реализации собственных методов аксессоров для коллекции ко-многим. Если они, все-же тем не менее, присутствуют, framework вызывает изменяемые методы (такие, как add<Key>Object: и remove<Key>Object:) при изменении коллекции, которая представляет собой постоянное отношение. (Cвойства выборки не поддерживают изменяемые методы аксессоров коллекций) для того, чтобы сделать все это правильно, вы должны реализовать add<Key>Object:/remove<Key>Object: в паре, add<Key>:/remove<Key>: в паре, или обе пары. Вы можете также осуществлять другие get акцессоры (например, countOf<Key>:, enumeratorOf<Key>: и memberOf<Key>:) и использовать их в своем коде, однако они не обязательно будут вызваны из framework.

Листинг 4 Класс управляемого объекта, иллюстрирующий выполнение пользовательских акцессоров для отношений ко-многим.

@interface Department : NSManagedObject
{

}
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSSet *employees;
@end
 

@interface Department (DirectReportsAccessors)

- (void)addEmployeesObject:(Employee *)value;
- (void)removeEmployeesObject:(Employee *)value;
- (void)addEmployees:(NSSet *)value;
- (void)removeEmployees:(NSSet *)value;

- (NSMutableSet*)primitiveEmployees;
- (void)setPrimitiveEmployees:(NSMutableSet*)value;
@end


@implementation Department

@dynamic name;
@dynamic employees;

- (void)addEmployeesObject:(Employee *)value
{
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];

    [self willChangeValueForKey:@"employees" withSetMutation:NSKeyValueUnionSetMutation
          usingObjects:changedObjects];

    [[self primitiveEmployees] addObject:value];
    [self didChangeValueForKey:@"employees" withSetMutation:NSKeyValueUnionSetMutation
          usingObjects:changedObjects];

    [changedObjects release];
}

- (void)removeEmployeesObject:(Employee *)value
{
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];

    [self willChangeValueForKey:@"employees" withSetMutation:NSKeyValueMinusSetMutation
          usingObjects:changedObjects];

    [[self primitiveEmployees] removeObject:value];
    [self didChangeValueForKey:@"employees" withSetMutation:NSKeyValueMinusSetMutation
          usingObjects:changedObjects];

    [changedObjects release];
}

- (void)addEmployees:(NSSet *)value
{
    [self willChangeValueForKey:@"employees" withSetMutation:NSKeyValueUnionSetMutation
          usingObjects:value];

    [[self primitiveEmployees] unionSet:value];
    [self didChangeValueForKey:@"employees" withSetMutation:NSKeyValueUnionSetMutation
          usingObjects:value];
}

- (void)removeEmployees:(NSSet *)value
{
    [self willChangeValueForKey:@"employees" withSetMutation:NSKeyValueMinusSetMutation
          usingObjects:value];

    [[self primitiveEmployees] minusSet:value];
    [self didChangeValueForKey:@"employees" withSetMutation:NSKeyValueMinusSetMutation
          usingObjects:value];
}

Пользовательские примитивные методы аксессоров

Примитивные методы доступа похожи на "нормальные" или общедоступные ключ-значение совместимые методы доступа, кроме того, что Core Data использует их как методы основных данных для доступа к данным, следовательно, они не выдают ключ-значение или уведомления наблюдения. Иными словами, они должны быть primitiveValueForKey, и setPrimitiveValue:forKey:, вто время, как общедоступные методы аксессора должны быть valueForKey, и setValue:forKey.

Обычно не должно быть никаких оснований для осуществления примитивных методов доступа. Они, однако, полезны, если вы хотите иметь пользовательские методы для обеспечения прямого доступа к переменным экземпляра постоянных свойств Core Data. В приведенном ниже примере контрастируют общедоступные и примитивные методы доступа к атрибуту, int16, тип Integer 16, хранимому в пользовательской переменной, например, nonCompliantKVCivar.

// primitive get accessor
- (short)primitiveInt16 {
    return nonCompliantKVCivar;
}

// primitive set accessor
- (void)setPrimitiveInt16:(short)newInt16 {
    nonCompliantKVCivar = newInt16;
}

// public get accessor
- (short)int16 {
    short tmpValue;
    [self willAccessValueForKey: @"int16"];
    tmpValue = nonCompliantKVCivar;
    [self didAccessValueForKey: @"int16"];
    return tmpValue;
}

// public set accessor
- (void)setInt16:(short)int16 {
    [self willChangeValueForKey: @"int16"];
    nonCompliantKVCivar = int16;
    [self didChangeValueForKey:@"int16"];
}
 
 
homeЗаметили ошибкукарта сайта 
   Made on a Mac