在视图控制器之间传递一个到多个核心数据 [英] Passing one to many core data between view controllers

查看:73
本文介绍了在视图控制器之间传递一个到多个核心数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

  WorkoutTypeVC 
WorkoutSetVC
WorkoutExerciseVC

我有三个实体,

  WorkoutType 
workouts( - > WorkoutSet)一到多
WorkoutSet
exercise( - > WorkoutExercise)一对多
workoutType( - > WorkoutType)Inverse
WorkoutExercise
workoutSet( - > WorkoutSet)Inverse

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



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



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



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

   - (void)fetchWorkoutTypes 
{
NSFetchRequest * fetchRequest =
[NSFetchRequest fetchRequestWithEntityName:@WorkoutType];
NSString * cacheName = [@WorkoutTypestringByAppendingString:@Cache];
NSSortDescriptor * sortDescriptor =
[NSSortDescriptor sortDescriptorWithKey:@workoutTypeascending: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 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)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 = .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 = [@WorkoutSetstringByAppendingString:@Cache];
NSSortDescriptor * sortDescriptor =
[NSSortDescriptor sortDescriptorWithKey:@workoutNameascending: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 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//返回节中的行数。
return self.workoutType.workouts.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * CellIdentifier = @细胞;
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 = [@WorkoutExercisestringByAppendingString:@Cache];
NSSortDescriptor * sortDescriptor =
[NSSortDescriptor sortDescriptorWithKey:@exerciseNameascending: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方法中。 (我假设)第二个(和第三个)
视图控制器中数据源的使用不一致。



在您的 WorkoutSetViewController 中, cellForRowAtIndexPath 通过 self.workoutType.workouts.allObjects ,但 didSelectRowAtIndexPath 使用提取的结果控制器(FRC)。这没有意义。如果表视图由FRC驱动,所有数据源方法必须使用FRC。



可能 self.fetchedResultsController nil 在第二个视图控制器?
然后,传递给第三个视图控制器的 workoutSet 将是 nil ,这将



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



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



而第三个视图控制器应该使用获取的结果控制器来显示与给定的<$ c相关的
all WorkoutExercise $ c> workoutSet 。



UPDATE: fetchWorkoutSets 在WorkoutSetVC.m中应该看起来像这样:

   - (void)fetchWorkoutSets 
{
NSFetchRequest * fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@WorkoutSet];
NSPredicate * predicate = [NSPredicate predicateWithFormat:@workoutType =%@,self.workoutType];
[fetchRequest setPredicate:predicate];
NSSortDescriptor * sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@workoutNameascending: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 相关的锻炼集。



同样, WorkoutExercise.m中的fetchWorkoutExercises 将使用谓词

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

只取得与 self.workoutSet



有关数据源方法,请查看 NSFetchedResultsController文档,它包含示例代码,您可以复制
并适应您的需要。或者,使用主 - 详细应用程序模板创建一个新的Xcode iOS应用程序,并选中核心数据复选框。这也将给你
样例代码。



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

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

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


I am having problems passing data between view controllers.

All three view controllers are table views.

 WorkoutTypeVC
 WorkoutSetVC
 WorkoutExerciseVC

I have three entities,

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

I am able to switch between all three view controllers, WorkoutTypeVC loads correctly showing all entries, When selected WorkoutSetVC is loaded showing the correct entries corresponding to the selection made from WorkoutTypeVC.

But when i select an entry from WorkoutSetVC, WorkoutExerciseVC loads but is empty, Even the title of the selection doesn't load.

I have used the same code which i used when switching from WorkoutTypeVC and WorkoutSetVC.

Below is the code for switching views in WorkoutType.m file:

-(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];

}

Below is the code for 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];
}

Below is the code for 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;
}

Not sure as to what i need to do for the third view controller to list all the entries, Even the title for the third view controller doesn't load which is coded in the ViewDidLoad Method.

Thank You

解决方案

The problem is (I assume) the inconsistent use of data sources in the second (and third?) view controller.

In your WorkoutSetViewController, cellForRowAtIndexPath accesses the objects directly via self.workoutType.workouts.allObjects, but didSelectRowAtIndexPath uses a fetched results controller (FRC). This does not make sense. If the table view is driven by a FRC, all data source methods must use the FRC.

Perhaps self.fetchedResultsController is nil in the second view controller? Then the workoutSet passed to the third view controller would be nil, which would explain that no title is set and no objects are displayed.

And generating an array from self.workoutType.workouts with allObjects is also problematic, because the order of the array elements can be random.

The second view controller should use a fetched results controller to display all WorkoutSet objects related to the given workoutType.

And the third view controller should use a fetched results controller to display all WorkoutExercise objects related to the given workoutSet.

UPDATE: fetchWorkoutSets in WorkoutSetVC.m should look like this:

-(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);
    }
}

The predicate is important to fetch only workout sets that are related to self.workoutType.

And similarly, fetchWorkoutExercises in WorkoutExercise.m would use the predicate

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

to fetch only exercises that are related to self.workoutSet.

For the data source methods, have a look at the NSFetchedResultsController documentation, it contains sample code that you can copy and adapt to your needs. Or you create a fresh Xcode iOS application with the "Master-Detail Application" template and select the "Core Data" checkbox. That will also give you sample code.

For example, in cellForRowAtIndexPath in WorkoutSetVC.m you would replace

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

by

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

这篇关于在视图控制器之间传递一个到多个核心数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆