0

I am developing small application in iOS (I am complete beginner). I have made a menu Core Data entity where I have categoryName and imageNamed saved. I want my UICollectionView in sections. But I am stuck in defining different indexPaths for different sections.

I also feel that my way of accessing data is very poor and seems inefficient as I am defining two NSFetchedResultsController instances. How can I access the data store better?

I get this error:

14-03-17 10:02:19.974 citiliving[1149:70b] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'

Error seems is out of bound so section is accessing something that is not in array boundaries.

Code to access data in 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);
    }
}

Note: I wanted to create object in variable which I can easily access in further code but I tried all variable could not do it.

Code used to get sections:

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

Finally getting everything in indexPath (here I am getting error as soon as I put 2nd section coding otherwise first section running ok:

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

I have only two sections and one has 5 rows and other have 6 rows. I wanted to make this one controller to access data and put everything in variables so later I can use variables. My database is categoryName | categoryImage | section

where section identify section one and two so I use predicate to make two different section using section field value.

4

2 回答 2

0

我终于把一切都弄好了,虽然希望可以让我的代码更干净,但不知道如何将两个 FRC 变成一个并使用 sectionNameKeyPath,但由于我必须将应用程序提交给管理层,所以我做了以下更改。

  1. 我按照韦恩先生的建议做了两个不同的缓存,它解决了错误问题。

但是在得到两个部分之后,我遇到了另一个选择索引的问题。当我单击一个部分但获得相同的 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;
}
}

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

于 2014-03-18T08:35:25.697 回答
0

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

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

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

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

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

(真的有点乱)

于 2014-03-17T10:33:03.797 回答