Преимущество переходных свойств обусловлено различием между смоделированными / наблюдаемыми свойствами и немоделированными / ненаблюдаемыми свойствами.
Контекст управляемого объекта использует наблюдение значения ключа (KVO) для мониторинга смоделированных свойств.На основе информации, предоставленной в модели данных, он знает, какие свойства должны иметь значения, какие значения по умолчанию, минимальные и максимальные значения, когда свойство изменяется и, что наиболее важно, имеет ли управляемый объект ключевое имя для свойства.Все это обеспечивает «управляемую» часть управляемых объектов.
Моделируемые свойства не требуют специального подкласса NSManagedObject, но могут использовать универсальный экземпляр NSManagedObject, инициализированный для сущности.Доступ к смоделированному свойству ошибки (см. Ниже) приводит к полной загрузке ошибки.
Контекст управляемого объекта не обнаруживает немоделированные свойства, а немоделированные свойства требуют специального подкласса NSManagedObject.Немоделированные свойства являются атрибутами только класса и не отображаются в сущности, и они никогда не сохраняются в Базовых данных.Изменения в немоделируемых свойствах остаются незамеченными контекстом.
Ошибки - это объекты-заполнители, которые определяют граф объектов со связями, но не загружают значения атрибутов.Вы можете думать о них как о «призрачных» объектах.Они будут регистрироваться как экземпляры NSManagedObject или частного _NSFault ... класса.Если это NSManagedObject, все атрибуты пусты.Когда ошибка «срабатывает» или «ошибается», объект-заполнитель заменяется полностью заполненным экземпляром NSManagedObject, атрибуты которого можно прочитать.
Поскольку немоделируемые свойства являются только атрибутами пользовательского подкласса NSManagedObject, а не сущностью, объекты сбоев ничего не знают о них.Объекты ошибок инициализируются из модели данных, поэтому все ключи, на которые они отвечают, должны быть в модели данных.Это означает, что ошибки не будут надежно отвечать на запрос о немоделируемых свойствах.
Переходные свойства решают эту проблему.Временное свойство предоставляет ключ, который контекст может наблюдать без сохранения.Если у вас есть ошибка, отправка ему сообщения о значении ключа для свойства тангенса вызовет контекст, чтобы «запустить» ошибку и загрузить весь управляемый объект.
Важно отметить, что хотя модель данных имеет ключевое имя для временного свойства, свойство имеет значение только тогда, когда управляемый объект полностью создан и загружен.Это означает, что при выполнении любых выборок, которые работают исключительно в постоянном хранилище, свойства касательной не будут иметь значений.
В вашем случае вы хотите использовать временное свойство для grid
, если значение grid
зависит от значений любых смоделированных свойств класса Board
.Это единственный способ гарантировать принудительно заставить Базовые данные гарантировать, что grid
всегда будет заполняться при обращении к нему.
[Редактировать: Последнее очень теоретическое.Использование переходного свойства гарантирует, что Core Data отслеживает свойство, так что доступ к свойству вызовет сбой и предоставит данные.Однако на практике доступ к любому смоделированному свойству надежно вызовет ошибку, и немоделируемые методы всегда доступны (см. Ниже).
Вы также можете использовать:
+[NSManagedObject contextShouldIgnoreUnmodeledPropertyChanges:]
… для принудительной установки контекстасмотреть немоделированные свойства.Однако это может вызвать непредвиденное и неуправляемое поведение, если немоделированные свойства имеют побочные эффекты.
Я думаю, что хорошей практикой является использование переходных свойств, когда это возможно, чтобы убедиться, что все покрыто. ]
Обновление:
Хорошо, но что, если у меня есть экземплярный метод, который не является средством доступа к свойству, как 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…
. С точки зрения кодировщиков, все эти разные объекты взаимозаменяемы.
- Даже если управляемый объект сообщает о сбое, он все равно будет реагировать на немоделированные селекторы.
- Доступ к любому смоделированному свойству приводит к возникновению ошибки и объект становится полностью активным.
- Базовые данные часто меняются объектами за кулисами, которые вы не можете контролировать и не должны беспокоиться о .
Короче, не беспокойтесь о немоделируемых свойствах и методах. Они должны работать прозрачно. Рекомендуется использовать переходные свойства, особенно если эти свойства имеют побочные эффекты с смоделированными свойствами. Вы можете заставить контекст отслеживать немоделированные свойства, но это может вызвать ненужную сложность.
Если у вас есть сомнения, просто проверьте себя на наличие ошибок, чтобы убедиться, что ваш класс работает.