1

ワークアウトというオブジェクトがあり、このオブジェクトはエクササイズというオブジェクトと 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++;
  }
}

4

3 に答える 3

1

同様の問題がありました。アプリの実行中は親子関係が機能していましたが、再起動後は最新の子レコードのみが取得されました。

私はこのように子供たちを追加していました:

  • 子レコードを作成する
  • 子の親属性を設定し、子の他の属性を設定します
  • 親の add メソッドを使用して子を親に追加します

次のようにすると修正されることがわかりました。

  • 子レコードを作成する
  • 親の add メソッドを使用して子を親に追加します
  • 子の親属性を設定し、子の他の属性を設定します
于 2012-10-13T22:47:27.963 に答える
0

私はこれとまったく同じ問題を抱えていますが、私のモデルはかなり複雑です。私のアプリは、エンティティとリレーションシップがまだ存在しない場合は、起動時にそれらを作成します。それらが作成され、アプリを終了しない場合、多対多の関係を持つエンティティをフェッチして、関連するオブジェクトの正しい数を確認できます。アプリを終了して再起動すると(デフォルトのデータセットを作成する必要がないことがわかります)、リレーションシップはnullセットを返します。私はそれを理解することはできません。

編集:私の問題は順序集合の関係に関連していることがわかりました。カテゴリを使用して、順序付けられたセットに新しいエントリを挿入するための回避策(スタックオーバーフローで見つかりました)を作成する必要がありました。だから、それはそれと関係があると思います。

于 2012-08-13T02:00:34.563 に答える
0

コア データは複雑です。何十ものチェック項目がある可能性があり、どれも問題の原因となっている可能性があります。

いくつの MOC を使用していますか? どうやって節約していますか?さらに多くの質問...

アプリケーションの起動時に引数の EditScheme で SQL デバッグ フラグ (-com.apple.CoreData.SQLDebug 1) をオンにすることをお勧めします。

コードを実行して、実際に何が起こっているかを確認してください。

リレーションシップは、フェッチ リクエストでオーバーライドしない限り、フェッチ時にフォルトに解決されます。

親子関係で複数の MOC を使用している場合、子から親への保存はデータを親に入れるだけで、実際には保存されません。UIManagedDocument を使用している場合、それはまったく異なる一連の問題です...

これが耳障りに聞こえないことを願っています。「これは保存されておらず、ここにデバッグ出力があります」以外の、Core Data の質問に対して多くの情報を提供できるように準備しておいてください。

基本的に、CoreData がどのように機能するかは、スタックの作成方法、UIManagedDocument を使用するかどうか、複数のスレッド、オブジェクトの作成方法、オブジェクトの保存方法、フェッチ リクエストのオプションなどによって異なります。

実際にはそれほど複雑ではありませんが、使用方法に応じて多くのカスタマイズと特殊なケースがあります。

編集

オブジェクト/関係を作成するコードを投稿してください。

また、テンプレートの代わりに手動フェッチ リクエストを使用してフェッチを試してください。データベース内のデータを見ると、関係の外部キーが適切に設定されていることがわかりますか?

デバッグを有効にしてもう一度実行し、SQL が何を行っているかを正確に確認します。これは、独自のデバッグ出力よりも価値があります。

于 2012-05-09T19:27:44.493 に答える