UIcollectionView cellForItemAtIndexPath仅在iOS 10中返回Null。在iOS 9和iOS 8中工作正常

UIcollectionView cellForItemAtIndexPath仅在iOS 10中返回Null。在iOS 9和iOS 8中工作正常,ios,uicollectionview,uicollectionviewcell,xcode8,ios10,Ios,Uicollectionview,Uicollectionviewcell,Xcode8,Ios10,我有一个应用程序,已经愉快地发布了几年。它在UICollectionView中检索RSS源。cellForItemAtIndexPath方法设置文本并调用datasource方法从提要中指定的链接加载图像。如果不存在,则加载网页数据并搜索标记以获取图像。找到/加载图像后,将调用委托方法将图像添加到单元格中。(下文) 在iOS 8和iOS 9中运行时,一切都很顺利,但在iOS 10中运行时,当RSS源最初加载时,可见单元格会更新为图像,但在滚动时,不会添加图像,并且cellForItemAtInd

我有一个应用程序,已经愉快地发布了几年。它在UICollectionView中检索RSS源。cellForItemAtIndexPath方法设置文本并调用datasource方法从提要中指定的链接加载图像。如果不存在,则加载网页数据并搜索
标记以获取图像。找到/加载图像后,将调用委托方法将图像添加到单元格中。(下文)

在iOS 8和iOS 9中运行时,一切都很顺利,但在iOS 10中运行时,当RSS源最初加载时,可见单元格会更新为图像,但在滚动时,不会添加图像,并且cellForItemAtIndexPath中的值为空

当我向后滚动时会显示该图像,如果我向imageWasLoadedForStory添加ReloadItemsAndExpaths,但ReloadItemsAndExpaths会破坏性能,则会显示该图像

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
           // ...    

          if (story.thumbnail) {
          [imageView setAlpha: 1.0];
          imageView.image = story.thumbnail;
          UIActivityIndicatorView *lActivity = (UIActivityIndicatorView *) [collectionView viewWithTag: 900];
          [lActivity removeFromSuperview];
          }else{
               [story setDelegate: self];
               [story findArticleImageForIndexPath: indexPath];
          }
          //  ...
}



//delegate method.  Called when image has been loaded for cell at specified indexpath

- (void) imageWasLoadedForStory: (RSSStory *) story forIndexPath: (NSIndexPath *) indexPath
{
        //get cell
        CustomCollectionViewCell *customCell = (id) [self.collectionview cellForItemAtIndexPath: indexPath];

        NSLog(@"imageWasLoadedForStory row %i section %i  and class %@", (int)indexPath.row, (int)indexPath.section, [customCell class]);

        //if cell is visible ie: cell is not nil then update imageview
        if (customCell) {
                 UIImageView *imageView = (UIImageView *) [customCell viewWithTag: 300];
                 imageView.image = story.thumbnail;
                 UIActivityIndicatorView *lActivity = (UIActivityIndicatorView *) [customCell viewWithTag: 900];
                 [lActivity removeFromSuperview];
                 [customCell setNeedsLayout];
                 [customCell setNeedsDisplay];
                 }
                    //[self.collectionview reloadItemsAtIndexPaths: [NSArray arrayWithObject: indexPath]];           
}



- (void) findArticleImageForIndexPath: (NSIndexPath *) indexPath
{
           //kick off image search
           dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

                self.thumbnail = [self findArticleForStoryForIndexPath:indexPath];
                dispatch_async( dispatch_get_main_queue(), ^{
                //image set - return
                      [self.delegate imageWasLoadedForStory: self forIndexPath: indexPath];
                });
        });
}

确保您正试图使用
[self.collectionview cellForItemAtIndexPath:indexPath]访问单元格。
是可见的

如果不可见,它将始终返回nil


您应该访问数据源(阵列、核心数据等),以获取显示在该单元中的数据,而不是访问单元本身。

我鼓励大家阅读预取-iOS 10中的新功能。简单的解决方案是:

[self.customCollectionview setPrefetchingEnabled:NO];
事实证明,单元格现在已预取。这意味着加载/不可见单元格与加载/可见单元格之间存在差异

在iOS 10中,单元格现在可以预加载,但如果不可见,它仍将返回nil。因此调用cellForItemAtIndexPath来预加载单元格。然后,完全有可能图像将完成加载,如果单元格不可见,cellForItemAtIndexPath将返回nil。这意味着不会设置imageView。滚动时,图像将不会添加到单元格中,因为单元格已创建

根据,这是由于预取,可禁用预取。当然,这也失去了预取的好处

苹果公司在文档中推荐的方法是在
collectionView(\ux0:willDisplay:forItemAt:)
中更新单元格外观

这样,单元格就可以在
cellForItem(at:)
中看到并可用于临时更新,或者不可见,但在滚动到视图中时会获取最新信息


另一个对我来说更简单的代码更改,同时保留预取的一些好处的替代方法是在
performBatchUpdates
块中使用调用
cellForItem(在indexPath中)
封装更新,例如:

类MyViewController:UIViewController{
@ibvar collectionView:UICollectionView!
...
func方法(){
...
collectionView.PerformBatchUpdate{
...
如果让cell=collectionView.cellForItem(at:indexPath)作为?MyCell{
//更新单元格,例如:
cell.someField=someValue
}
...
}完成:{uin}
...
}
...
}
显然,
performBatchUpdates
调用会丢弃在
collectionView(\uu:cellForItemAt:)
中准备好但尚未可见(由于预取)的任何单元格


不幸的是,这些被丢弃的单元似乎不会再次被预取,只有在它们变得可见时才会被重新加载。所以预取的一些好处已经失去了。

好吧,我可能不是疯了。我已经能够通过使用tag属性使其工作。在cellForItemAtIndexPath中,我添加了:[CellSetTag:indexPath.row];在我的委托方法中添加了:CustomCollectionViewCell*customCell=(CustomCollectionViewCell*)[self.collectionview viewWithTag:indexPath.row];这使得一切都正常,但我不认为这是一个规则的方式来处理这个问题。谢谢。如果看不见,我希望是零,但奇怪的是,如果我在iOS9上运行,它工作得非常完美。此外,如果我改为添加一个与单元格行相等的标记属性,并使用:CustomCollectionViewCell*customCell=(CustomCollectionViewCell*)[self.collectionview viewWithTag:indexPath.row]检索单元格,它在iOS 9和iOS 10中也能完美工作;令人沮丧的。如果我缓慢滚动,则返回nil。i、 e.单元格已创建,但在加载图像时仍不可见。如果我快速滚动到某个单元格,则它会工作,即返回加载的图像,并且该单元格可见。非常感谢Joe:)。不幸的是,您的解决方案在我的情况下不起作用。我在我的
viewDidLoad()
中设置了
self.collectionView.isPrefetchingEnabled=false
,但是当我在
diddelectitemat indexPath:
中调用
cellForItem(at:)
时,我仍然返回了
nil
。你所描述的肯定还有其他事情。(即错误的索引XPath等)如果有人正在选择单元格,则必须加载该单元格。只有在显示单元格之前才会应用预取。i、 e.用户向下滚动,单元格2到8可见。在iOS 10中,9到15个单元格被预加载,以期变得可见。这是唯一一次预取是个问题。有几个小时,我认为我有一个线程问题,这就是为什么事情没有正确加载。谢谢