Я прочитал документацию о переходных свойствах, но я не могу понять их цели. Может ли кто-нибудь сказать мне разницу между наличием и отсутствием свойства переходного процесса, если у меня есть собственный подкласс NSManagedObject, подобный этому?
@interface Board : NSManagedObject
{
NSMutableArray *_grid;
}
// Core Data to-many relationship
@property (nonatomic, retain) NSSet *pieces;
@property (nonatomic, readonly) NSArray *grid;
-(void)awake;
-(void)movePiece:(PieceState *)piece to_x:(int)x y:(int)y;
@end
@implementation Board
@dynamic pieces;
-(void)awakeFromInsert {
[super awakeFromInsert];
[self awake];
}
-(void)awakeFromFetch {
[super awakeFromFetch];
[self awake];
}
-(void)awake {
_grid = nil; // probably not necessary
}
-(NSArray *)grid {
if (!_grid) {
_grid = [[NSMutableArray alloc] initWithCapacity:10];
for (int i = 0; i < 10; i++) {
NSMutableArray *column = [[NSMutableArray alloc] initWithCapacity:10];
[_grid addObject:column];
for (int j = 0; j < 10; j++)
[column addObject:[NSNull null]];
[column release];
}
for (PieceState *piece in self.pieces)
if (piece.x >= 0 && piece.y >= 0)
[[_grid objectAtIndex:piece.x] replaceObjectAtIndex:piece.y withObject:piece];
}
return _grid;
}
-(void)movePiece:(PieceState *)piece to_x:(int)x y:(int)y {
if (x >= 0 && y >= 0) {
NSObject *capturedPieceObject = [[self.grid objectAtIndex:x] objectAtIndex:y];
if ([capturedPieceObject isKindOfClass:[PieceState class]]) {
PieceState *capturedPiece = (PieceState *)capturedPieceObject;
[self removePiecesObject:capturedPiece];
[[self managedObjectContext] deleteObject:capturedPiece];
capturedPiece = nil;
}
}
if (_grid) {
if (piece.x >= 0 && piece.y >= 0)
[[_grid objectAtIndex:piece.x] replaceObjectAtIndex:piece.y withObject:[NSNull null]];
if (x >= 0 && y >= 0)
[[_grid objectAtIndex:x] replaceObjectAtIndex:y withObject:piece];
}
[piece setX:x];
[piece setY:y];
}
- (void)didTurnIntoFault {
[_grid release];
_grid = nil;
[super didTurnIntoFault];
}
@end
Итак, части и сетка представляют два способа доступа к тем же данным. куски - это фактическое свойство отношений с основными данными и представляет собой плотный список всех частей. grid - это способ найти содержимое определенного пространства на доске, адресованное координатами (x, y). сетка создается лениво и обновляется (пока она существует), когда кусок меняет местоположение.
Я не объявляю сетью как свойство переходного процесса, и все работает нормально. Мне просто интересно, есть ли какие-то необычные условия, которые могут возникнуть, что может вызвать ошибку, если я не объявляю свойство переходного процесса.
Я думаю, что я читаю переходные свойства, необходимые для правильного поведения отмены, если вы делаете производное свойство, подобное этому. Я не использую отмену, и в любом случае я не вижу, как это может работать в этом случае. Если движение части отменено, менеджер отмены может присвоить ему старое значение _grid (возможно, если я не сделал его только для чтения), но старое значение совпадает с новым значением. Это указатель на тот же экземпляр NSMutableArray, только содержимое изменилось. Во всяком случае, я не использую отмену.
Итак, получаю ли я какую-либо выгоду, если объявляю сетью переходное свойство?
Дополнительный вопрос. Что делать, если у меня есть такой код:
Board *board = someOtherManagedObject.board;
NSObject *boardContents = [[board.grid objectAtIndex:5] objectAtIndex:5];
Возможно ли, что плата является ошибкой после доступа к someOtherManagedObject.board? У меня тоже проблемы с пониманием ошибки. Я думаю, что в этом случае мой код сработает. Я заметил, что бодрствующий набор _grid ник. Я думаю, что последовательность будет такой:
- grid getter называется
- _grid выделено
- Доступ к self.pieces
- сбои в неисправности
- awake называется
-
_grid = nil
- возврат в сетку getter
-
[[_grid objectAtIndex:...
значение доступа nil, сбой или, по крайней мере, no-op - grid getter возвращает nil
- сбой или неправильное поведение, когда ожидается, что boardContents будет содержать значение
С другой стороны, возможно, если я объявлю, что сетка является временным свойством, тогда ошибка срабатывает до того, как вызывается мой сетчатый приемник?
От TechZen:
Ошибки - это объекты-заполнители, которые определяют граф объекта с отношениями, но не загружают значения атрибутов. Они будут регистрироваться как экземпляры либо NSManagedObject, либо частного класса _NSFault...
Поскольку немоделированные свойства являются только атрибутами настраиваемого подкласса NSManagedObject, а не сущности, объекты сбоя ничего не знают о них. Объекты дефектов инициализируются из модели данных, поэтому все ключи, на которые они отвечают, должны быть в модели данных. Это означает, что неисправности не будут надежно отвечать на запрос немоделированных свойств.
Подождите, что? Я начинаю понимать, что мои объекты могут быть ошибками в любое время, но вы говорите мне, что они могут даже быть экземплярами моего класса!? Или, если вы используете пользовательский подкласс, они гарантированы как вид сбоев, которые являются экземплярами NSManagedObject (в частности, моего подкласса)?
Если они не являются экземплярами пользовательского класса, то что происходит с чем-то вроде этого:
@interface Foo : NSManagedObject {
int data;
}
@property (nonatomic, retain) NSString *modeledProperty;
-(void)doSomething;
@end
@implementation Foo
@dynamic modeledProperty;
-(void)doSomething {
data++;
}
@end
Что произойдет, если я вызову doSomething по ошибке?
- Не реагирует на селектор, авария
- Запускает мой код, но мои переменные экземпляра не существуют, кто знает, что происходит, когда он выполняет данные ++
- существуют данные, только modeledProperty не существует, потому что это ошибка
Свойства переходного процесса устраняют эту проблему. Свойство transient предоставляет ключ, который контекст может наблюдать без сохранения. Если у вас есть ошибка, отправка сообщения с ключом для свойства касательной вызовет контекст, чтобы "запустить" ошибку и загрузить полный управляемый объект.
Хорошо, но что, если у меня есть метод экземпляра, который не является аксессуаром свойства, например doSomething выше? Как я могу убедиться, что у меня есть реальный объект, прежде чем я его назову? Или я могу его назвать, и, прежде всего, в теле метода убедитесь, что у меня есть реальный объект (например, путем доступа к моделируемому свойству)?
В вашем случае вы хотите использовать свойство переходного процесса для сетки, если значение сетки зависит от значений любых смоделированных свойств класса Board. Это единственный способ гарантировать, что сетка будет всегда заполняться при ее доступе.
Я думал, что если это зависело от значений смоделированных свойств, тогда оно срабатывало бы, когда оно зависело от них, т.е. строка for (PieceState *piece in self.pieces)
срабатывает, потому что она обращается к self.pieces, которая является модельным свойством. Но вы говорите мне, что?
- Я даже не могу вызвать метод grid getter при ошибке
- Я могу назвать это, но я не могу использовать _grid так, как хочу
Кажется, если я понимаю, что вы говорите, и это правда, пользовательские подклассы NSManagedObject очень ограничены.
- У них не могут быть какие-либо методы экземпляра, которые не являются моделируемыми атрибутами свойств или сеттерами, потому что объект не может быть гарантированно существовать в работоспособном состоянии при их вызове. (Исключение: методы экземпляров, которые являются только вспомогательными методами для аксессуаров свойств, будут в порядке.)
- Они не могут иметь никаких переменных экземпляра для какой-либо полезной цели, кроме временных кешей вычисляемых значений, поскольку эти переменные экземпляра могут быть стерты в любой момент. Я знаю, что они не будут сохранены на диске, но я думал, что они будут, по крайней мере, сохранены, пока я сохраняю объект в памяти.
Если это так, вы не собираетесь ставить логику приложения в свои пользовательские подклассы NSManagedObject? Если логика приложения находится в других классах, имеющих ссылки на управляемые объекты, а управляемые объекты - это только тупые объекты, от которых вы читаете и записываете (только немного умный, с некоторыми возможностями для обеспечения согласованности данных)? Является единственной точкой подклассификации NSManagedObject для выполнения некоторых "трюков" с нестандартными типами данных?