0

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

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

 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 方法中编码的。

谢谢你

4

1 回答 1

0

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

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

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

self.workoutType.workouts并且从with生成数组allObjects也是有问题的,因为数组元素的顺序可以是随机的。

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

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

更新: fetchWorkoutSets在 WorkoutSetVC.m 中应该如下所示:

-(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在 WorkoutExercise.m 中将使用谓词

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

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

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

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

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

经过

WorkoutSet *workoutSet = [self.fetchedResultsController objectAtIndexPath:indexPath];
于 2013-08-17T19:43:59.880 回答