使用 UICollection 中的部分访问数据库

Posted

技术标签:

【中文标题】使用 UICollection 中的部分访问数据库【英文标题】:Accessing database using sections in UICollection 【发布时间】:2014-03-17 06:15:44 【问题描述】:

我正在 ios 中开发小型应用程序(我是初学者)。我制作了一个菜单核心数据实体,其中保存了categoryNameimageNamed。我想要我的UICollectionView 分段。但我坚持为不同的部分定义不同的indexPaths。

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

我收到此错误:

14-03-17 10:02:19.974 citiliving[1149:70b] * 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“* -[__NSArrayM objectAtIndex:]:索引 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 行。我想让这个控制器访问数据并将所有内容放入变量中,以便以后可以使用变量。 我的数据库是 类别名称 |类别图片 |部分

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

【问题讨论】:

【参考方案1】:

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

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

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

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

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

(真的有点乱)

【讨论】:

Wain,关于缓存名称工作表的建议。现在我的它正在工作。但我真的想要你的建议如何让它干净,因为它真的很乱。其次,我再次遇到问题,因为当我执行 objectAtIndex:selectedIndexPath.row] 时,我得到了第二部分 indexPath,因为我必须在他们点击其内容的位置进行编码。 那么,你能用一个单一的 FRC 和 sectionNameKeyPath:@"section" 吗? Wain,感谢您的快速回复,我已经搜索了很多关于 sectionNameKeyPath 的内容,但没有找到如何实现它?如果我使用一个带有部分字段的 FRC,我将如何使用数据库值对两个部分进行排序。有没有办法使用一个 FRC 并在 indexPath 的编码中根据字段区分部分? 索引路径为您提供sectionitem 数字。这就是sectionNameKeyPath 的用途。尝试使用它 老实说,我是新手,所以仍然不清楚如何使用它?我需要在我的数据库中进行更改吗?请您帮助更正参考网站,我可以确切地了解如何使用它!抱歉,我承认我的开发初期,但需要提供完整的产品,并在自学中学习所有内容。【参考方案2】:

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

    我按照 Wain 先生的建议制作了两个不同的缓存,它解决了错误问题。

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


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

【讨论】:

以上是关于使用 UICollection 中的部分访问数据库的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS swift 中的 ARSCNView 中显示 uicollection 视图

视频库的UICollection

4.UiCollection API 详细介绍

UICollection 在使用 Swift 3 显示图像时非常慢

Table Cell 中的 UICollection 视图在 Swift 3 中不显示图像

在单独的 UICollection 类中使用未解析的标识符“UICollection”