使用UICollection中的节访问数据库

时间:2014-03-17 06:15:45

标签: ios core-data uicollectionview nsfetchedresultscontroller nsrangeexception

我正在开发iOS中的小应用程序(我是完全初学者)。我已经创建了一个菜单Core Data实体,其中保存了categoryNameimageNamed。我想要我的UICollectionView部分。但我不得不为不同的部分定义不同的indexPath

我还觉得我访问数据的方式非常差,而且因为我定义了两个NSFetchedResultsController个实例,所以效率似乎很低。如何更好地访问数据存储?

我收到此错误:

  

14-03-17 10:02:19.974 citiliving [1149:70b] *由于未捕获的异常'NSRangeException'终止应用程序,原因:'* - [__ NSArrayM objectAtIndex:]:index 1超出界限[0 .. 0]'

错误似乎超出了界限,因此部分正在访问不在数组边界内的内容。

访问viewDidLoad中的数据的代码:

- (void)viewDidLoad
{
    [super viewDidLoad];

    testAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *managedObjectContext = [appDelegate managedObjectContext];

    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Menu"];
    NSString *cacheName = [@"Menu" stringByAppendingString:@"Cache"];

    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"categoryName" ascending:YES];
    NSPredicate* pred = [NSPredicate predicateWithFormat:@"section = %@", @"dining"];

    fetchRequest.predicate = pred; // req is the NSFetchRequest we're configuring
    [fetchRequest setSortDescriptors:@[sortDescriptor]];

    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:cacheName ];

    NSError *error;
    if (![self.fetchedResultsController performFetch:&error])
    {
        NSLog(@"Fetch failed: %@", error);
    }
    else
    {
        NSLog(@"Records found: number %lu", (unsigned long)self.fetchedResultsController.fetchedObjects.count);     
    }

    NSFetchRequest *fetchRequestMenuTwo = [NSFetchRequest fetchRequestWithEntityName:@"Menu"];
    NSString *cacheNameTwo = [@"Menu" stringByAppendingString:@"Cache"];

    NSSortDescriptor *sortDescriptorTwo = [NSSortDescriptor sortDescriptorWithKey:@"categoryName" ascending:YES];
    NSPredicate* predTwo = [NSPredicate predicateWithFormat:@"section = %@", @"information"];

    fetchRequestMenuTwo.predicate = predTwo; // req is the NSFetchRequest we're configuring
    [fetchRequestMenuTwo setSortDescriptors:@[sortDescriptorTwo]];

    self.fetchedResultsControllerTwo = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequestMenuTwo managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:cacheNameTwo ];

    //NSError *error;
    if (![self.fetchedResultsControllerTwo performFetch:&error])
    {
        NSLog(@"Fetch failed: %@", error);
    }
    else
    {
        NSLog(@"Records found at 2nd fetch: number %lu", (unsigned long)self.fetchedResultsControllerTwo.fetchedObjects.count);
    }
}

注意:我想在变量中创建对象,我可以在其他代码中轻松访问,但我尝试了所有变量都无法实现。

用于获取部分的代码:

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    switch (section) {
        case 0:
            return self.fetchedResultsController.fetchedObjects.count;
        case 1:
            return self.fetchedResultsControllerTwo.fetchedObjects.count;
        default:
            return 0;
    }
}

-(NSString *)nameForSection:(NSInteger)index
{
    switch(index)
    {
        case 0:
            return @"Section One";
        case 1:
            return @"Section Two";
        default:
            return @"Unknown";
    }
}

最后把所有内容都放在indexPath中(我在第二部分编码时出现错误,否则第一部分运行正常:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *identifier = @"Cell";

    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

    switch (indexPath.section) {
        case 0:
        {
            Menu *menu = (Menu *)[self.fetchedResultsController objectAtIndexPath:indexPath];
            UIImageView *cityLivingImageView = (UIImageView *)[cell viewWithTag:100];
            UILabel *cityLivingLabel = (UILabel *)[cell viewWithTag:200];
            cityLivingLabel.text = menu.categoryName;
            cityLivingImageView.image    = [UIImage imageNamed:menu.imageName];

            NSLog(@"Record found: %@", menu.categoryName );

            return cell;
        }
        case 1:
        {
            Menu *menu = (Menu *)[self.fetchedResultsControllerTwo objectAtIndexPath:indexPath];
            UIImageView *cityLivingImageView = (UIImageView *)[cell viewWithTag:100];
            UILabel *cityLivingLabel = (UILabel *)[cell viewWithTag:200];
            cityLivingLabel.text = menu.categoryName;
            cityLivingImageView.image    = [UIImage imageNamed:menu.imageName];

            NSLog(@"Record found: %@", menu.categoryName );

            return cell;        
        }
        default:
        break;
    }

    return cell;    
}

我只有两个部分,一个有5行,另外有6行。我想让这个控制器访问数据并将所有内容放在变量中以便稍后我可以使用变量。 我的数据库是 categoryName | categoryImage |节

其中section标识第一部分和第二部分,因此我使用谓词使用section字段值创建两个不同的部分。

2 个答案:

答案 0 :(得分:0)

第一个问题是Menu个对象对section键有多少不同的值?通常,您应该使用单个提取结果控制器(FRC)并使用section作为sectionNameKeyPath

FRC设置的另一个问题是两者都使用具有相同名称的缓存。这将无法正常工作,因为每个FRC都有不同的谓词。确保缓存名称是唯一的或删除缓存名称并设置为nil。

你的崩溃是因为你正在使用2个FRC,但是你只对待第二个FRC。你正在创建一个包含2个部分的集合视图,但每个FRC只能理解一个部分。您的第一部分有效,因为部分编号(零)与第一个FRC预期的匹配。但是,第二部分的部分编号为1,不匹配,因此您会得到范围异常。

如果可以,您应该将代码更改为仅使用一个FRC(如果您希望数据存储中的每个不同的section值都有一个部分)。如果没有,您可以通过将代码更改为:

来修复崩溃
NSIndexPath *fabricatedIndexPath = [NSIndexPath indexPathForItem:indexPath.item inSection:0];
Menu *menu = (Menu *)[self.fetchedResultsControllerTwo objectAtIndexPath:fabricatedIndexPath];

(真的有点麻烦)

答案 1 :(得分:0)

我终于使一切正确,虽然希望可以使我的代码更清晰,但不知道如何从两个FRC到一个并使用sectionNameKeyPath,但因为我必须向管理层提交应用程序,所以我做了以下更改。

  1. 我按照Wain先生的建议制作了两个不同的缓存,它解决了错误问题。
  2. 但是在得到两个部分后,我遇到了另一个选择索引的问题。当我点击一个部分但得到相同的indexPath时,我使用if循环来查看确切的部分是什么,并使用两个转换的FRC来对象,而不是分配部分精确路径。我的选择部分如下。我知道它很乱,但时间限制使我这样做。

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
    if ([[segue identifier] isEqualToString:@"showCategoriesMenu"])
    {
        NSIndexPath *selectedIndexPath = [[self.collectionView indexPathsForSelectedItems] objectAtIndex:0];
        SubMenuTableViewController *subMenuViewController = [segue destinationViewController];
    
        NSString *clickedCell;
    
        if (selectedIndexPath.section == 1)
        {
        Menu *menu = (Menu *)[itemsMenuTwo  objectAtIndex:selectedIndexPath.row];
            clickedCell = menu.categoryName;
        }
        else
        {
        Menu *menu = (Menu *)[itemsMenuOne  objectAtIndex:selectedIndexPath.row];
            clickedCell = menu.categoryName;
        }
        subMenuViewController.title = clickedCell;
        subMenuViewController.categoryName = clickedCell;
    }
    }
    

    感谢您的支持,我真的很感激。