UIcollectionView cellForItemAtIndexPath returns 仅在 iOS 10 中为空。在 iOS 9 和 iOS 8 中工作正常
UIcollectionView cellForItemAtIndexPath returns Null in iOS 10 only. Works fine in iOS 9 and iOS 8
我有一个应用程序已经运行了几年。它在 UICollectionView 中检索 RSS 提要。 cellForItemAtIndexPath 方法设置文本并调用数据源方法以从提要中指定的 link 加载图像。如果 none 存在,它会加载网页数据并搜索 <img>
标签以获取图像。一旦图像为 found/loaded,就会调用委托方法将图像添加到单元格中。 (下)
当 运行 在 iOS 8 和 9 时,一切都很好,但是当 运行 在 iOS 10 时,当 RSS 提要是最初加载但滚动时没有添加图像,我从 cellForItemAtIndexPath 得到 NULL。
当我向后滚动时显示图像,如果我将 reloadItemsAtIndexPaths 添加到 imageWasLoadedForStory 但 reloadItemsAtIndexPaths 会破坏性能。
- (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]
访问的单元格
可见。
如果不可见,它将始终 return nil。
您应该访问您的数据源(数组、核心数据等)以获取您在该单元格中显示的数据,而不是访问单元格本身。
我鼓励大家阅读预取 - iOS10 中的新功能。简单的解决方案是:
[self.customCollectionview setPrefetchingEnabled:NO];
事实证明,单元格现在已预取。这意味着现在 loaded/nonvisible 个单元格和 loaded/visible 个单元格之间存在差异。
在 iOS 10 中,现在可以预加载一个单元格,但如果它不可见,它仍然会 return nil。因此调用 cellForItemAtIndexPath 来预加载单元格。然后完全有可能图像将完成加载并且 cellForItemAtIndexPath 将 return nil 如果单元格不可见。这意味着将不会设置 imageView。滚动时不会将图像添加到单元格,因为单元格已经创建。
根据 这是由于预取,可以禁用。当然,这也失去了预取的好处。
Apple 在 collectionView(_:cellForItemAt:)
的文档中推荐的方法是更新 collectionView(_:willDisplay:forItemAt:)
中的单元格外观。
这样,单元格要么可见并可从 cellForItem(at:)
获得临时更新,要么不可见但在滚动到视图中时获取最新信息。
另一种选择 对我有用,代码更改更简单,同时保留预取的 一些 好处是通过调用包装更新cellForItem(at indexPath)
在 performBatchUpdates
块内,例如:
class MyViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
...
func someMethod() {
...
collectionView.performBatchUpdates {
...
if let cell = collectionView.cellForItem(at: indexPath) as? MyCell {
// Update cell, e.g.:
cell.someField = someValue
}
...
} completion: { _ in }
...
}
...
}
显然,performBatchUpdates
调用会丢弃在 collectionView(_:cellForItemAt:)
中准备但尚不可见(由于预取)的所有单元格。
不幸的是,那些丢弃的单元格似乎没有再次预取,只有在它们可见时才会重新加载。所以预取的一些好处就丢失了。
我有一个应用程序已经运行了几年。它在 UICollectionView 中检索 RSS 提要。 cellForItemAtIndexPath 方法设置文本并调用数据源方法以从提要中指定的 link 加载图像。如果 none 存在,它会加载网页数据并搜索 <img>
标签以获取图像。一旦图像为 found/loaded,就会调用委托方法将图像添加到单元格中。 (下)
当 运行 在 iOS 8 和 9 时,一切都很好,但是当 运行 在 iOS 10 时,当 RSS 提要是最初加载但滚动时没有添加图像,我从 cellForItemAtIndexPath 得到 NULL。
当我向后滚动时显示图像,如果我将 reloadItemsAtIndexPaths 添加到 imageWasLoadedForStory 但 reloadItemsAtIndexPaths 会破坏性能。
- (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]
访问的单元格
可见。
如果不可见,它将始终 return nil。
您应该访问您的数据源(数组、核心数据等)以获取您在该单元格中显示的数据,而不是访问单元格本身。
我鼓励大家阅读预取 - iOS10 中的新功能。简单的解决方案是:
[self.customCollectionview setPrefetchingEnabled:NO];
事实证明,单元格现在已预取。这意味着现在 loaded/nonvisible 个单元格和 loaded/visible 个单元格之间存在差异。
在 iOS 10 中,现在可以预加载一个单元格,但如果它不可见,它仍然会 return nil。因此调用 cellForItemAtIndexPath 来预加载单元格。然后完全有可能图像将完成加载并且 cellForItemAtIndexPath 将 return nil 如果单元格不可见。这意味着将不会设置 imageView。滚动时不会将图像添加到单元格,因为单元格已经创建。
根据
Apple 在 collectionView(_:cellForItemAt:)
的文档中推荐的方法是更新 collectionView(_:willDisplay:forItemAt:)
中的单元格外观。
这样,单元格要么可见并可从 cellForItem(at:)
获得临时更新,要么不可见但在滚动到视图中时获取最新信息。
另一种选择 对我有用,代码更改更简单,同时保留预取的 一些 好处是通过调用包装更新cellForItem(at indexPath)
在 performBatchUpdates
块内,例如:
class MyViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
...
func someMethod() {
...
collectionView.performBatchUpdates {
...
if let cell = collectionView.cellForItem(at: indexPath) as? MyCell {
// Update cell, e.g.:
cell.someField = someValue
}
...
} completion: { _ in }
...
}
...
}
显然,performBatchUpdates
调用会丢弃在 collectionView(_:cellForItemAt:)
中准备但尚不可见(由于预取)的所有单元格。
不幸的是,那些丢弃的单元格似乎没有再次预取,只有在它们可见时才会重新加载。所以预取的一些好处就丢失了。