ワークアウトというオブジェクトがあり、このオブジェクトはエクササイズというオブジェクトと 1 対多の関係にあります。
モデルの図: http://i.imgur.com/q1Mfq.png
ワークアウト オブジェクトを作成するときに、ループを実行して 3 つのエクササイズ オブジェクトを追加します。
[self addExercisesObject:exercise]
次に、管理対象オブジェクトのコンテキストを保存します。次に、ワークアウトを表示するためのコントローラーから、デバッガーの出力に示されているように、ワークアウトとそのエクササイズを (フェッチ要求で) 正常に取得できます。
Printing description of self->_savedWorkout:
<Workout: 0x6c5a990> (entity: Workout; id: 0x6e46e00 <x-coredata://EA417EAA-101A-4F04-8276-3C4A6CDF094D/Workout/p1> ; data: {
bodyweight = nil;
date = "2012-05-09 16:59:43 +0000";
exercises = (
"0x6e3c870 <x-coredata://EA417EAA-101A-4F04-8276-3C4A6CDF094D/Exercise/p3>",
"0x6e3eaf0 <x-coredata://EA417EAA-101A-4F04-8276-3C4A6CDF094D/Exercise/p2>",
"0x6e36820 <x-coredata://EA417EAA-101A-4F04-8276-3C4A6CDF094D/Exercise/p1>"
);
isCompleted = 0;
workoutId = 1;
workoutPlan = "0x6e6c980 <x-coredata://EA417EAA-101A-4F04-8276-3C4A6CDF094D/WorkoutPlan/p1>";
})
ここまでは順調ですね。ただし、シミュレーターでアプリを閉じて再度起動し、同じビューで同じフェッチ要求を実行すると、ワークアウトは次のようになります。
Printing description of self->_savedWorkout:
<Workout: 0x6ea8ff0> (entity: Workout; id: 0x6e8f9e0 <x-coredata://EA417EAA-101A-4F04-8276-3C4A6CDF094D/Workout/p1> ; data: {
bodyweight = nil;
date = "2012-05-09 16:59:43 +0000";
exercises = (
);
isCompleted = 0;
workoutId = 1;
workoutPlan = "0x6c8a130 <x-coredata://EA417EAA-101A-4F04-8276-3C4A6CDF094D/WorkoutPlan/p1>";
})
同じワークアウト オブジェクトを取得しているように見えますが、今の演習は空のセットです。実際には、取得リクエストの後、演習は最初に次のようになります。
exercises = "<relationship fault: 0x8a93100 'exercises'>";
しかし、私がしたら:
for (Exercise *exercise in self.savedWorkout.exercises)
self.savedWorkout.exercises は空のセットに解決されます。とにかく、アプリのどの部分でもワークアウトを編集しません。
私のフェッチ要求は、ワークアウト クラスのこのメソッドによって行われます。
- (Workout *)getLatestWorkout
{
self.model = [[self.managedObjectContext persistentStoreCoordinator] managedObjectModel];
NSFetchRequest *fetchRequest = [self.model fetchRequestTemplateForName:@"getLatestWorkout"];
NSError *error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if ([results count] == 1) {
return [results objectAtIndex:0];
}
return nil;
}
XcodeのGUIツールでfetch requestのテンプレートを作りました。it fetches all Workout objects where isCompleted == 0. ワークアウトの x-coredata パスが両方のデバッガー出力で同じであるため、毎回同じオブジェクトをフェッチすることがわかります。
更新: SQLite データベースを確認しました。ワークアウト テーブルには 1 つのワークアウトがあり、エクササイズ テーブルには 3 つのエクササイズがあります。
何が起こっているのですか?
編集: 以下に投稿されたオブジェクトを作成するコード
- (void)storeUserSettings
{
// get the file path if it exists
NSString *path = [[NSBundle mainBundle] pathForResource:@"userSettings" ofType:@"plist"];
// create it if it doesn't
if (path == nil) {
path = [NSString stringWithFormat:@"%@%@",
[[NSBundle mainBundle] bundlePath], @"/userSettings.plist"];
}
// and write the new settings to file
[self.userSettings writeToFile:path atomically:YES];
// load managed object context
[self loadMOC];
WorkoutPlan *currentPlan = [[WorkoutPlan alloc] getActiveWorkoutPlan];
[currentPlan setManagedObjectContext:self.managedObjectContext];
// if user has no plan or is changing plans, create new plan and first workout
if (currentPlan == nil ||
([self.userSettings valueForKey:@"plan"] != currentPlan.planId)) {
// create a workoutPlan object
WorkoutPlan *workoutPlan = [[WorkoutPlan alloc] initWithEntity:
[NSEntityDescription entityForName:@"WorkoutPlan"
inManagedObjectContext:self.managedObjectContext]
insertIntoManagedObjectContext:self.managedObjectContext];
// set attributes to values from userSettings and save object
[workoutPlan createWorkoutPlanWithId:[self.userSettings valueForKey:@"plan"]
schedule:[self.userSettings valueForKey:@"schedule"]
dateStarted:[self.userSettings valueForKey:@"nextDate"]];
}
// if user is just changing schedule, update schedule of current plan
else if (![currentPlan.schedule isEqualToString:[self.userSettings valueForKey:@"schedule"]]) {
[currentPlan setSchedule:[self.userSettings valueForKey:@"schedule"]];
[currentPlan saveMOC];
}
}
- (void)loadMOC
{
AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = delegate.managedObjectContext;
self.model = [[self.managedObjectContext persistentStoreCoordinator] managedObjectModel];
}
- (void)createWorkoutPlanWithId:(NSNumber *)planId schedule:(NSString *)schedule
dateStarted:(NSDate *)dateStarted
{
[self deactivateCurrentPlan];
// set workout plan attributes
[self setPlanId:planId];
[self setIsActive:[NSNumber numberWithBool:YES]];
[self setSchedule:schedule];
[self setDateStarted:dateStarted];
// create first workout and add to workout plan
Workout *firstWorkout = [NSEntityDescription
insertNewObjectForEntityForName:@"Workout"
inManagedObjectContext:self.managedObjectContext];
[firstWorkout setManagedObjectContext:self.managedObjectContext];
[firstWorkout createFirstWorkoutForPlan:self onDate:dateStarted];
[self addWorkoutsObject:firstWorkout];
[self saveMOC];
}
- (void)createFirstWorkoutForPlan:(WorkoutPlan *)plan onDate:(NSDate *)startDate
{
// set workout attributes
[self setDate:startDate];
[self setIsCompleted:[NSNumber numberWithBool:NO]];
[self setWorkoutId:[NSNumber numberWithInt:1]];
NSArray *exerciseList = [self getExercisesForWorkout:self inPlan:plan];
// iterate over exercises in spec and create them
for (NSDictionary *exerciseSpec in exerciseList)
{
// create a exercise MO
Exercise *exercise = [NSEntityDescription
insertNewObjectForEntityForName:@"Exercise"
inManagedObjectContext:[plan managedObjectContext]];
[exercise setManagedObjectContext:[plan managedObjectContext]];
[exercise createExerciseForWorkout:self withSpec:exerciseSpec];
// add exercise to workout object
[self addExercisesObject:exercise];
}
}
- (void)createExerciseForWorkout:(Workout *)workout withSpec:exerciseSpec
{
// set exercise attributes
self.exerciseId = [exerciseSpec valueForKey:@"id"];
self.isPersonalRecord = [NSNumber numberWithBool:NO];
NSArray *sets = [exerciseSpec valueForKey:@"sets"];
int i = 1;
for (NSNumber *setReps in sets)
{
// create a set MO
Set *set = [NSEntityDescription
insertNewObjectForEntityForName:@"Set"
inManagedObjectContext:[workout managedObjectContext]];
[set setManagedObjectContext:[workout managedObjectContext]];
// set set attributes
set.order = [NSNumber numberWithInt:i];
set.repetitions = setReps;
set.weight = [exerciseSpec valueForKey:@"default_weight"];
// add set to exercise object
[self addSetsObject:set];
i++;
}
}