使用 UICollection 中的部分访问数据库
Posted
技术标签:
【中文标题】使用 UICollection 中的部分访问数据库【英文标题】:Accessing database using sections in UICollection 【发布时间】:2014-03-17 06:15:44 【问题描述】:我正在 ios 中开发小型应用程序(我是初学者)。我制作了一个菜单核心数据实体,其中保存了categoryName
和imageNamed
。我想要我的UICollectionView
分段。但我坚持为不同的部分定义不同的indexPath
s。
我还觉得我访问数据的方式很差,而且似乎效率低下,因为我定义了两个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 的编码中根据字段区分部分?
索引路径为您提供section
和item
数字。这就是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 在使用 Swift 3 显示图像时非常慢