在视图控制器之间传递一个到多个核心数据

我在视图控制器之间传递数据时遇到问题。

所有三个视图控制器都是表视图。

WorkoutTypeVC WorkoutSetVC WorkoutExerciseVC 

我有三个实体,

 WorkoutType workouts(->WorkoutSet) One to Many WorkoutSet exercises(->WorkoutExercise) One to Many workoutType(->WorkoutType) Inverse WorkoutExercise workoutSet(->WorkoutSet) Inverse 

我可以在所有三个视图控制器之间切换,WorkoutTypeVC正确加载正确显示所有条目,当选择WorkoutSetVC时,加载显示与WorkoutTypeVC选择对应的正确条目。

但是当我从WorkoutSetVC中选择一个条目时,WorkoutExerciseVC加载但是为空,甚至不加载选择的标题。

我使用了从WorkoutTypeVC和WorkoutSetVC切换时使用的相同代码。

下面是在WorkoutType.m文件中切换视图的代码:

 -(void)fetchWorkoutTypes { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"WorkoutType"]; NSString *cacheName = [@"WorkoutType" stringByAppendingString:@"Cache"]; NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"workoutType" ascending:YES]; [fetchRequest setSortDescriptors:@[sortDescriptor]]; self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:cacheName]; NSError *error; if (![self.fetchedResultsController performFetch:&error]) { NSLog(@"Fetch failed: %@", error); } } - (void)viewDidAppear:(BOOL)animated{ [self fetchWorkoutTypes]; [self.tableView reloadData]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return self.fetchedResultsController.fetchedObjects.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } WorkoutType *workoutType = (WorkoutType *)[self.fetchedResultsController objectAtIndexPath:indexPath]; cell.textLabel.text = workoutType.workoutType; cell.detailTextLabel.text = [NSString stringWithFormat:@"(%d)", workoutType.workouts.count]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { WorkoutType *workoutType = (WorkoutType *)[self.fetchedResultsController objectAtIndexPath:indexPath]; WorkoutSetViewController *detailViewController = [[WorkoutSetViewController alloc] initWithWorkoutType:workoutType]; [self.navigationController pushViewController:detailViewController animated:YES]; } 

下面是WorkoutSetVC.m的代码

 -(void)fetchWorkoutSets { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"WorkoutSet"]; NSString *cacheName = [@"WorkoutSet" stringByAppendingString:@"Cache"]; NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"workoutName" ascending:YES]; [fetchRequest setSortDescriptors:@[sortDescriptor]]; self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:cacheName]; NSError *error; if (![self.fetchedResultsController performFetch:&error]) { NSLog(@"Fetch failed: %@", error); } } - (id)initWithWorkoutType:(WorkoutType *)workoutType { self = [super initWithStyle:UITableViewStylePlain]; if (self) { self.workoutType = workoutType; } return self; } - (void)viewDidLoad { [super viewDidLoad]; self.title = self.workoutType.workoutType; [self fetchWorkoutSets]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return self.workoutType.workouts.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } WorkoutSet *workoutSet = [self.workoutType.workouts.allObjects objectAtIndex:indexPath.row]; cell.textLabel.text = workoutSet.workoutName; cell.detailTextLabel.text = [NSString stringWithFormat:@"(%d)", workoutSet.exercises.count]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { WorkoutSet *workoutSet = (WorkoutSet *)[self.fetchedResultsController objectAtIndexPath:indexPath]; WorkoutExerciseTableViewController *detailViewController = [[WorkoutExerciseTableViewController alloc] initWithWorkoutSet:workoutSet]; [self.navigationController pushViewController:detailViewController animated:YES]; } 

下面是WorkoutExercise.m的代码

 - (id)initWithWorkoutSet:(WorkoutSet *)workoutSet { self = [super initWithStyle:UITableViewStylePlain]; if (self) { self.workoutSet = workoutSet; } return self; } -(void)fetchWorkoutExercises { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"WorkoutExercise"]; NSString *cacheName = [@"WorkoutExercise" stringByAppendingString:@"Cache"]; NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"exerciseName" ascending:YES]; [fetchRequest setSortDescriptors:@[sortDescriptor]]; self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:cacheName]; NSError *error; if (![self.fetchedResultsController performFetch:&error]) { NSLog(@"Fetch failed: %@", error); } } - (void)viewDidLoad { [super viewDidLoad]; self.title = self.workoutSet.workoutName; [self fetchWorkoutExercises]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } WorkoutExercise *exercise = [self.workoutSet.exercises.allObjects objectAtIndex:indexPath.row]; cell.textLabel.text = exercise.exerciseName; return cell; } 

不确定我需要做什么让第三个视图控制器列出所有条目,甚至第三个视图控制器的标题也不加载在ViewDidLoad方法中编码的。

谢谢

问题是(我假设)在第二个(和第三个?)视图控制器中不一致地使用数据源。

WorkoutSetViewControllercellForRowAtIndexPath直接通过self.workoutType.workouts.allObjects访问对象,但didSelectRowAtIndexPath使用获取的结果控制器(FRC)。 这根本不符合逻辑。 如果表视图由FRC驱动,则所有数据源方法都必须使用FRC。

也许self.fetchedResultsController在第二个视图控制器中是nil ? 然后传递给第三个视图控制器的workoutSet将为nil ,这将解释没有设置标题并且不显示任何对象。

并且使用allObjectsself.workoutType.workouts生成数组也是有问题的,因为数组元素的顺序可以是随机的。

第二个视图控制器应使用获取的结果控制器来显示与给定的workoutType相关的所有WorkoutSet对象。

第三个视图控制器应使用获取的结果控制器来显示与给定的workoutSet相关的所有WorkoutExercise对象。

更新: fetchWorkoutSets中的fetchWorkoutSets应如下所示:

 -(void)fetchWorkoutSets { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"WorkoutSet"]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"workoutType = %@", self.workoutType]; [fetchRequest setPredicate:predicate]; NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"workoutName" ascending:YES]; [fetchRequest setSortDescriptors:@[sortDescriptor]]; self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; self.fetchedResultsController.delegate = self; NSError *error; if (![self.fetchedResultsController performFetch:&error]) { NSLog(@"Fetch failed: %@", error); } } 

谓词对于仅获取与self.workoutType相关的训练集非常重要。

同样, fetchWorkoutExercises中的fetchWorkoutExercises将使用谓词

  NSPredicate *predicate = [NSPredicate predicateWithFormat:@"workoutSet = %@", self.workoutSet]; [fetchRequest setPredicate:predicate]; 

仅获取与self.workoutSet相关的self.workoutSet

对于数据源方法,请查看NSFetchedResultsController文档 ,它包含可以复制并适应您需求的示例代码。 或者使用“Master-Detail Application”模板创建一个全新的Xcode iOS应用程序,然后选中“Core Data”复选框。 这也将为您提供示例代码。

例如,在WorkoutSetVC.m中的cellForRowAtIndexPath中,您将替换

 WorkoutSet *workoutSet = [self.workoutType.workouts.allObjects objectAtIndex:indexPath.row]; 

通过

 WorkoutSet *workoutSet = [self.fetchedResultsController objectAtIndexPath:indexPath];