Ответ 1
Преимущество переходных свойств заключается в различии между смоделированными/наблюдаемыми свойствами и немоделированными/ненаблюдаемыми свойствами.
Контекст управляемого объекта использует наблюдение за ключевым значением (KVO) для мониторинга смоделированных свойств. На основе информации, представленной в модели данных, она знает, какие свойства должны иметь значения, каковы значения по умолчанию, минимальные и максимальные значения, когда свойство изменено и, что наиболее важно, имеет ли управляемый объект ключевое имя для свойства. Все это обеспечивает "управляемую" часть управляемых объектов.
Моделируемые свойства не требуют настраиваемого подкласса NSManagedObject, но могут использовать общий экземпляр NSManagedObject, инициализированный для объекта. Доступ к моделируемому свойству неисправности (см. Ниже) приводит к полной загрузке ошибки.
Контекст управляемого объекта не учитывает немоделированные свойства, а для немоделированных свойств требуется собственный подкласс NSManagedObject. Немоделированные свойства являются атрибутами только класса и не отображаются в сущности, и они никогда не сохраняются в Core Data. Изменения в немоделированных свойствах остаются незамеченными контекстом.
Ошибки - это объекты-заполнители, которые определяют граф объекта с отношениями, но не загружают значения атрибутов. Вы можете думать о них как о "призракных" объектах. Они будут регистрироваться как экземпляры либо NSManagedObject, либо частного класса _NSFault.... Если это NSManagedObject, все атрибуты пусты. Когда ошибка "срабатывает" или "сбой", объект-заполнитель заменяется полностью заполненным экземпляром NSManagedObject, чьи атрибуты могут быть прочитаны.
Поскольку немоделированные свойства являются только атрибутами настраиваемого подкласса NSManagedObject, а не сущности, объекты сбоя ничего не знают о них. Объекты дефектов инициализируются из модели данных, поэтому все ключи, на которые они отвечают, должны быть в модели данных. Это означает, что неисправности не будут надежно отвечать на запрос немоделированных свойств.
Свойства переходного процесса устраняют эту проблему. Свойство transient предоставляет ключ, который контекст может наблюдать без сохранения. Если у вас есть ошибка, отправка сообщения с ключом для свойства касательной вызовет контекст, чтобы "запустить" ошибку и загрузить полный управляемый объект.
Важно отметить, что хотя модель данных имеет ключевое имя для свойства переходного процесса, свойство имеет только значение, когда управляемый объект полностью создается и загружается. Это означает, что когда вы делаете какие-либо выборки, которые работают исключительно в постоянном хранилище, тангенциальные свойства не будут иметь значений.
В вашем случае вы хотите использовать свойство transient для grid
, если значение grid
зависит от значений любых смоделированных свойств класса Board
. Это единственный способ гарантировать принудительное использование Core Data, чтобы гарантировать, что grid
всегда будет заполняться при доступе к нему.
[Edit: Это последнее очень теоретическое. Использование свойства transient гарантирует, что Core Data отслеживает свойство таким образом, что доступ к свойству приведет к сбою и предоставлению данных. Тем не менее, на практике доступ к любому смоделированному свойству будет надежно запускать ошибку, и немоделированные методы всегда доступны (см. Ниже).
Вы также можете использовать:
+[NSManagedObject contextShouldIgnoreUnmodeledPropertyChanges:]
... заставить контекст просматривать немодельные свойства. Однако это может вызвать непредвиденное и неуправляемое поведение, если немоделированные свойства имеют побочные эффекты.
Я думаю, что это хорошая практика использовать временные свойства, когда это возможно, чтобы убедиться, что все покрыто. ]
Обновление:
Хорошо, но что, если у меня есть метод экземпляра, который не является свойством Accessor, как doSomething выше? Как я могу убедиться, что у меня есть реальный объект, прежде чем я его назову?
Я думаю, вы закончили думать об этом, и мое громоздкое объяснение ничего не помогло.
Core Data управляет всеми этими проблемами для вас. Я использую Core Data, если есть Core Data, и я никогда не сталкивался с какими-либо проблемами. Основные данные не будут очень полезными, если вам придется постоянно останавливаться и проверять, были ли объекты неисправными или нет.
Например, я создал простую модель с такими классами:
Alpha:
@class Beta;
@interface Alpha : NSManagedObject {
@private
}
@property (nonatomic, retain) NSNumber * num;
@property (nonatomic, retain) NSString * aString;
@property (nonatomic, retain) NSSet *betas;
-(NSString *) unmodeledMethod;
@end
@interface Alpha (CoreDataGeneratedAccessors)
- (void)addBetasObject:(Beta *)value;
- (void)removeBetasObject:(Beta *)value;
- (void)addBetas:(NSSet *)values;
- (void)removeBetas:(NSSet *)values;
@end
@implementation Alpha
@dynamic num;
@dynamic aString;
@dynamic betas;
-(NSString *) unmodeledMethod{
return @"Alpha class unmodeledMethod return value";
}
@end
Бета:
@class Alpha;
@interface Beta : NSManagedObject {
@private
}
@property (nonatomic, retain) NSNumber * num;
@property (nonatomic, retain) NSSet *alphas;
-(NSString *) unmodeledMethod;
-(NSString *) accessModeledProperty;
@end
@interface Beta (CoreDataGeneratedAccessors)
- (void)addAlphasObject:(Alpha *)value;
- (void)removeAlphasObject:(Alpha *)value;
- (void)addAlphas:(NSSet *)values;
- (void)removeAlphas:(NSSet *)values;
@end
@implementation Beta
@dynamic num;
@dynamic alphas;
-(NSString *) unmodeledMethod{
return [NSString stringWithFormat:@"%@ isFault=%@", self, [self isFault] ? @"YES":@"NO"];
}
-(NSString *) accessModeledProperty{
return [NSString stringWithFormat:@"\n isFault =%@ \n access numValue=%@ \n isFault=%@", [self isFault] ? @"YES":@"NO", self.num,[self isFault] ? @"YES":@"NO"];
}
@end
Затем я создал объектный граф объекта Alpha
со связанным объектом Beta
. Затем я перезапустил приложение и выполнил выборку всех объектов Alpha
. Затем я зарегистрировал следующее:
id aa=[fetchedObjects objectAtIndex:0];
id bb=[[aa valueForKey:@"betas"] anyObject];
NSLog(@"aa isFault= %@",[aa isFault] ? @"YES":@"NO");
//=> aa isFault= NO
NSLog(@"\naa = %@",aa);
//=> aa = <Alpha: 0x63431b0> (entity: Alpha; id: 0x6342780 <x-coredata://752A19D9-2177-45A9-9722-61A40973B1BC/Alpha/p1> ; data: {
//=> aString = "name 2";
//=> betas = (
//=> "0x63454c0 <x-coredata://752A19D9-2177-45A9-9722-61A40973B1BC/Beta/p7>"
//=> );
//=> // ignore fetchedProperty = "<relationship fault: 0x6153300 'fetchedProperty'>";
//=> num = 0;
//=> })
NSLog(@"\nbb isFault= %@",[bb isFault] ? @"YES":@"NO");
//=> bb isFault= YES
NSLog(@"\nany beta = %@",[[bb class] description]);
//=> any beta = Beta
NSLog(@"\n-[Beta unmodeledMethod] =\n \n %@",[bb unmodeledMethod]);
//=> -[Beta unmodeledMethod] =
//=> <Beta: 0x639de70> (entity: Beta; id: 0x639dbf0 <x-coredata://752A19D9-2177-45A9-9722-61A40973B1BC/Beta/p7> ; ...
//=>...data: <fault>) isFault=YES
NSLog(@"\n-[Beta accessModeledProperty] = \n %@",[bb accessModeledProperty]);
-[Beta accessModeledProperty] =
//=> isFault =NO
//=> access numValue=2
//=> isFault=YES
NSLog(@"\nbb = %@",bb);
//=>bb = <Beta: 0x6029a80> (entity: Beta; id: 0x6029460 <x-coredata://752A19D9-2177-45A9-9722-61A40973B1BC/Beta/p7> ; data: {
//=> alphas = "<relationship fault: 0x60290f0 'alphas'>";
//=> num = 2;
//=>})
Обратите внимание, что:
- Оба
aa
иbb
устанавливаются в ожидаемый класс, даже несмотря на то, что я назначил общий объект. Контекст гарантирует, что выборка возвращает правильный класс. - Даже
bb
классBeta
он сообщает как ошибку, означающую, что объект представляет экземпляр классаBeta
, но что ни одно из его смоделированных свойств не заполнено. - Объект
bb
отвечает на селекторunmodeledMethod
, хотя в рамках метода он все еще сообщает об ошибке. - Доступ к моделируемому свойству
Beta.num
преобразуетbb
из-за ошибки даже до вызова (компилятор устанавливает его для запуска), но как только доступ выполняется, он возвращается обратно к ошибке. - Объектами в отношениях являются не только ошибки, но и те же объекты, которые возвращаются путем обращения к этой связи. В
Alpha.betas
объектBeta
имеет адрес0x63454c0
, тогда какbb
имеет адрес0x639de70>
, пока он является ошибкой. После того, как он преобразуется из отказа, а затем обратно, он имеет адрес0x6029a80
. Однако идентификатор managedObjectID всех трех объектов одинаковый.
Мораль здесь:
- "ошибки" - это больше о состоянии управляемого объекта и меньше о фактическом классе. В зависимости от способа доступа к объекту вы можете получить фактический подкласс или получить экземпляр скрытых классов
_NSFault…
. С точки зрения кодеров все эти разные объекты взаимозаменяемы. - Даже если управляемый объект сообщает об ошибке, он все равно будет реагировать на немоделированные селектор.
- Доступ к любому смоделированному свойству приводит к тому, что ошибка срабатывает, и объект становится полностью активным.
- В Core Data выполняется очень много операций по замене объектов за кулисами, которые вы не можете контролировать и не должны беспокоиться о.
Короче говоря, не беспокойтесь о немоделированных свойствах и методах. Они должны работать прозрачно. Лучше всего использовать переходные свойства, особенно если эти свойства имеют побочные эффекты с смоделированными свойствами. Вы можете заставить контекст отслеживать немодельные свойства, но это может вызвать ненужную сложность.
Если у вас есть сомнения, просто выполните тест самостоятельно на наличие ошибок, чтобы убедиться, что ваш класс работает.