一時的なプロパティに関するドキュメントを読みましたが、その目的を本当に理解できません。このような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
したがって、ピースとグリッドは、同じデータにアクセスするための2つの方法を提供します。pieceは、実際のCore Dataリレーションシッププロパティであり、すべてのpieceの密なリストです。グリッドは、(x、y)座標でアドレス指定されたボード上の特定のスペースの内容を見つける方法です。グリッドは遅延して構築され、ピースが場所を変更すると(存在する限り)更新されます。
グリッドを一時的なプロパティとして宣言しているわけではなく、すべてが正常に機能しています。一時的なプロパティを宣言しないとバグを引き起こす可能性のある異常な状態が発生する可能性があるかどうか疑問に思っています。
このような派生プロパティを実行している場合、適切な元に戻る動作を取得するには、一時的なプロパティが必要であると私は思います。私はundoを使用していませんが、いずれにせよ、この場合にどのように機能するかわかりません。ピースの移動が取り消された場合、元に戻すマネージャーは_gridの古い値を元に戻すことができます(おそらく読み取り専用にしないと仮定します)が、古い値は新しい値と同じです。これは同じNSMutableArrayインスタンスへのポインタであり、内容のみが変更されています。とにかく、undoは使いません。
では、グリッドを一時的なプロパティとして宣言した場合、何らかのメリットがありますか?
追加の質問。このようなコードがある場合はどうなりますか?
Board *board = someOtherManagedObject.board;
NSObject *boardContents = [[board.grid objectAtIndex:5] objectAtIndex:5];
someOtherManagedObject.boardにアクセスした後、ボードに障害が発生している可能性はありますか?私も障害を理解するのに苦労しています。その場合、私のコードはクラッシュすると思います。アウェイクが_gridをnilに設定していることに気づきました。シーケンスは次のようになると思います。
- グリッドゲッターと呼ばれる
- _グリッドが割り当てられました
- アクセスされたself.pieces
- 障害火災
- 目覚めと呼ばれる
_grid = nil
- グリッドゲッターに戻る
[[_grid objectAtIndex:...
nil値にアクセスする、クラッシュする、または少なくとも何もしない- グリッドゲッターは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を呼び出すとどうなりますか?
- セレクターに応答しない、クラッシュ
- コードを実行しますが、インスタンス変数が存在しません。data++を実行するとどうなるかを知っています。
- データは存在しますが、modeledPropertyは障害であるため存在しません
一時的なプロパティはこの問題を修正します。一時プロパティは、コンテキストが保存せずに監視できるキーを提供します。障害が発生した場合、一時プロパティのKey-Valueメッセージを送信すると、コンテキストが障害を「発生」させ、完全な管理対象オブジェクトをロードします。
わかりましたが、上記のdoSomethingのように、プロパティアクセサーではないインスタンスメソッドがある場合はどうなりますか?呼び出す前に、実際のオブジェクトがあることを確認するにはどうすればよいですか?または、それを呼び出すことはできますか?メソッド本体の最初のことは、実際のオブジェクトがあることを確認します(たとえば、モデル化されたプロパティにアクセスすることによって)?
あなたの場合、グリッドの値がボードクラスのモデル化されたプロパティの値に依存する場合は、グリッドに一時的なプロパティを使用する必要があります。これは、グリッドにアクセスしたときにグリッドに常にデータが入力されることを保証する唯一の方法です。
モデル化されたプロパティの値に依存している場合、それらに依存しているときに障害が発生する、つまり、for (PieceState *piece in self.pieces)
モデル化されたプロパティであるself.piecesにアクセスするため、ラインが障害を発生させると思いました。しかし、あなたは私にどちらを言っているのですか?
- 障害時にグリッドゲッターメソッドを呼び出すことさえできません
- 呼び出すことはできますが、_gridを思い通りに使用できません
あなたの言っていることが理解できれば、それは本当のようですが、NSManagedObjectのカスタムサブクラスは非常に限られています。
- オブジェクトが呼び出されたときに使用可能な状態で存在することが保証されないため、モデル化されたプロパティゲッターまたはセッターではないインスタンスメソッドを持つことはできません。(例外:プロパティアクセサーのヘルパーメソッドにすぎないインスタンスメソッドで問題ありません。)
- これらのインスタンス変数はいつでも消去される可能性があるため、計算値の一時キャッシュ以外の有用な目的でインスタンス変数を持つことはできません。それらがディスクに永続化されないことはわかっていますが、オブジェクトをメモリに保持している限り、少なくとも永続化されると思いました。
その場合、カスタムNSManagedObjectサブクラスにアプリケーションロジックを配置するつもりはありませんか?アプリケーションロジックは、管理対象オブジェクトへの参照を持つ他のクラスに存在する必要があり、管理対象オブジェクトは、読み取りと書き込みを行うダムオブジェクトのみです(データの一貫性を維持するためのいくつかの機能を備えた、少しスマートです)。NSManagedObjectをサブクラス化して、非標準のデータ型でいくつかの「トリック」を実行する唯一のポイントはありますか?