数据源方法collectionView:numberOfItemsInSection:崩溃应用程序“索引0超出空数组的范围”
Posted
技术标签:
【中文标题】数据源方法collectionView:numberOfItemsInSection:崩溃应用程序“索引0超出空数组的范围”【英文标题】:Datasource method collectionView: numberOfItemsInSection: Crashes App "index 0 beyond bounds for empty array" 【发布时间】:2014-05-05 04:02:48 【问题描述】:我整天都在处理这个代码,所以它可能只是我忽略的一些愚蠢的东西,但我似乎无法找出问题所在,我无计可施。
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
if(collectionView == self.titleBarCollectionView)
return 1;
NSInteger photoCount = [[self.fetchedResultsController fetchedObjects] count];
NSInteger sectionCount = (photoCount + 3) / 3;
return sectionCount;
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
if(collectionView != self.titleBarCollectionView)
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
NSInteger numberInSection = [sectionInfo numberOfObjects];
if(numberInSection < 3) numberInSection++;
return numberInSection;
return 3;
我有一个显示用户照片的 UICollectionView。照片取自核心数据,但是集合视图中的第一个索引(项目 0,第 0 部分)被替换为“添加照片”图像,并且所有照片的 indexPaths 都进行了调整以适应这一点。它工作了好几个小时,但由于某种原因在删除应用程序(重置核心数据)后,我似乎什至无法加载视图。当它到达id sectionInfo = [self.fetchedResultsController sections][section];
行时,它会立即崩溃并显示错误<strong>* Terminating app due to uncaught exception 'NSRangeException', reason: '*</strong> -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
。我这辈子都想不通。这是我的其余数据源方法。
-(void)configureCell:(UICollectionViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
if([cell.reuseIdentifier isEqualToString:@"Profile Title Cell"])
... Irrelevant code ...
else if(indexPath.row == 0 && indexPath.section == 0)
UIImageView *imageView = (UIImageView *)[cell viewWithTag:300];
imageView.image = [UIImage imageNamed:@"plusIcon.png"];
else
NSIndexPath *newIndexPath = [self newIndexPathFromIndexPath:indexPath];
Photo *photo = [self.fetchedResultsController objectAtIndexPath:newIndexPath];
UIImageView *imageView = (UIImageView *)[cell viewWithTag:300];
NSData *imageData = [[NSData alloc] initWithBase64EncodedString:photo.thumbnailData options:0];
imageView.image = [UIImage imageWithData:imageData];
if(photo.imageData)
imageView.image = [UIImage imageWithData:photo.imageData];
else if(photo.imageURL && ![photo.imageURL isEqualToString:@""])
NSString *imageURL = [NSString stringWithFormat:@"%@%@", PHOTOS_BASE_URL, photo.imageURL];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
self.activeThreads += 1;
NSData *imageURLData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]];
dispatch_async(dispatch_get_main_queue(), ^
photo.imageData = imageURLData;
[self.imageCollectionView reloadItemsAtIndexPaths:@[indexPath]];
self.activeThreads -= 1;
if(self.activeThreads < 1)
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
);
);
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
UICollectionViewCell *cell = nil;
if(collectionView == self.titleBarCollectionView)
cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Profile Title Cell" forIndexPath:indexPath];
else
cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Profile Image Cell" forIndexPath:indexPath];
[self configureCell:cell atIndexPath:indexPath];
return cell;
- (NSIndexPath *)newIndexPathFromIndexPath:(NSIndexPath *)indexPath
NSInteger row = 0;
NSInteger section = 0;
if(indexPath.row > 0)
row = indexPath.row - 1;
section = indexPath.section;
else
row = 2;
section = indexPath.section - 1;
return [NSIndexPath indexPathForItem:row inSection:section];
编辑:这是我的 fetchedResultsController 设置器
- (NSFetchedResultsController *)fetchedResultsController
if(!_fetchedResultsController)
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];
fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"uploadDate" ascending:YES]];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"ownerID == %@", self.currentUser.userID];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext
sectionNameKeyPath:@"sectionIdentifier"
cacheName:nil];
_fetchedResultsController.delegate = self;
[_fetchedResultsController performFetch:nil];
return _fetchedResultsController;
【问题讨论】:
这可能是因为您创建了 UICollectionView 的属性并忘记将其与界面生成器连接。请检查它是否已连接。 @sahebSingh 是的,它已连接。就像我说的,它工作了一段时间,所以我不认为它有什么大不了的。 如错误所示,您的数组之一为空。检查数组中的数据。 @Pankaj 是的,我知道,[self.fetchedResultsController sections][section]
数组是空的,但它不应该是因为self.fetchedResultsController's fetchedObjects
返回 8 个对象。
崩溃发生时section
的值是多少?
【参考方案1】:
您在评论中说fetchedObjects
返回 8 个对象。在numberOfSectionsInCollectionView
中,您使用它来计算集合视图中的部分数量:
NSInteger photoCount = [[self.fetchedResultsController fetchedObjects] count];
NSInteger sectionCount = (photoCount + 3) / 3;
return sectionCount;
假设计数确实是 8,这意味着 sectionCount
是 3(11 / 3
,整数除法)。请注意,您不是在询问 fetched results controller 它有多少个部分,而是告诉集合视图它应该包含三个部分。
由于您在上面返回 3,collectionView:numberOfItemsInSection:
将被调用 3 次,其中部分值为 0、1 和 2。您将 section
值传递给获取的结果控制器:
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
这仅在获取的结果控制器实际上有 3 个部分时才有效。 但你从来没有问过它有多少部分,所以不能保证它有那么多部分。在这种情况下,极有可能发生崩溃。
看起来发生的事情是:
您在创建提取结果控制器时没有使用sectionNameKeyPath
因此[self.fetchedResultsController sections]
返回一个空数组
但是您尝试在该空数组中查找一个对象,因为您假设会有 3 个部分而不检查这是否正确。
因此你崩溃了。您不能只告诉 fetched results 控制器它应该有多少个部分。部分的数量基于提取结果,除非包含sectionNameKeyPath
,否则没有任何部分。
【讨论】:
我编辑了我的帖子以显示我的fetchedResultsController
的二传手。我正在使用sectionNameKeyPath
,它可以容纳额外的单元格并将每张照片放在它所属的部分中。
我已将其标记为答案,因为它是正确的,但是,我在单独的答案中包含了为我解决问题的代码,以防其他人将来遇到此问题。
好的,你确实有一个sectionNameKeyPath
,但你仍然不能假设获取的结果控制器至少有 3 个部分。【参考方案2】:
原来collectionView:numberOfItemsInSection:
是在NSFetchedResultsController
执行performFetch:
之前被调用的,因此[self.fetchedResultsController sections]
是空的。为了解决这个问题,我只是用一些简单的逻辑手动设置每个部分的项目数。
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
NSArray *fetchedObjects = [self.fetchedResultsController fetchedObjects];
NSInteger count = [fetchedObjects count] + 1;
NSInteger sections = count / 3;
if(sections > section) return 3;
else return count % 3;
【讨论】:
以上是关于数据源方法collectionView:numberOfItemsInSection:崩溃应用程序“索引0超出空数组的范围”的主要内容,如果未能解决你的问题,请参考以下文章
数据源方法collectionView:numberOfItemsInSection:崩溃应用程序“索引0超出空数组的范围”
为啥我的collectionView中的单元格的形成速度比接收数据的方法快,因为它们的形成?