【发布时间】:2014-11-11 22:11:02
【问题描述】:
我在数据来自 cloudkit 的集合视图中加载图像时遇到线程问题。我知道这是一个线程/阻塞问题,因为在我实现 CK 之前,我将一些图像转储到我桌面上的一个文件夹中并从那里读取/解析它们并且没有问题。使用 CK,我只是通过仪表板创建了一些记录,我成功地返回了预期的记录,并使用这些结果中的图像来填充 CV 单元格。我将 CK 查询结果存储在一个数组中,并使用该数组的大小来设置 numberOfItemsInSection 委托。
这是问题所在...在 numberOfItemsInSection 委托方法中,我正在调用执行 CK 查询的模型类。因为这显然是一个网络调用,所以我把它放在后台线程中。从日志中,我可以看到查询执行并且结果很快就回来了——在 2-3 秒内。但是,CV 单元格从不显示,并且我没有看到自定义单元格被初始化(通过日志记录)。但是,如果我点击相机按钮并拍摄我已经实现的照片,我会拍摄生成的图像并将其添加到数组中,然后在 CV 上调用 reloadData 并出现所有单元格(和图像),包括新图像刚用相机拍的。
偶然地,我发现了一个有点工作的技巧,它在 CV inside numberOfItemsInSection 委托方法的后台线程上调用 reloadData。结果,我想我可能通过在调用 reloadData 时切换回主线程而偶然发现了解决方案,但这将其置于一种不断调用 numberOfItemsInSection 方法和 cellForItemAtIndexPath 的无限循环中,并使其滞后以至于您几乎无法滚动并点击任何单元格都不会做任何事情。
在这一点上,在尝试了很多很多不同的事情之后,我完全不知道如何解决这个问题。我知道这可能是一个非常简单的解决方案,因为异步加载图像以填充 collectionview 或 tableview 是很常见的。有人可以提供一些指导吗?提前谢谢!!!
@property (nonatomic) NSInteger numberOfItemsInSection;
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
NSLog(@"***numberOfItemsInSection***");
dispatch_queue_t fetchQ = dispatch_queue_create("load image data", NULL);
dispatch_async(fetchQ, ^{
self.numberOfItemsInSection = [self.imageLoadManager.imageDataArray count];
[self.myCollectionView reloadData]; // should be done on main thread!
});
NSLog(@"numberOfItemsInSection: %ld", (long)self.numberOfItemsInSection);
return self.numberOfItemsInSection;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell"; // string value identifier for cell reuse
ImageViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
NSLog(@"cellForItemAtIndexPath: section:%ld row:%ld", (long)indexPath.section, (long)indexPath.row);
cell.layer.borderWidth = 1.0;
cell.layer.borderColor = [UIColor grayColor].CGColor;
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
ImageData *imageData = [self.imageLoadManager imageDataForCell:indexPath.row]; // maps the model to the UI
dispatch_async(dispatch_get_main_queue(), ^{
if (imageData.imageURL.path) {
cell.imageView.image = [UIImage imageWithContentsOfFile:imageData.imageURL.path];
[cell setNeedsLayout];
} else {
// if imageURL is nil, then image is coming in from the camera as opposed to the cloud
cell.imageView.image = imageData.image;
[cell setNeedsLayout];
}
});
return cell;
}
【问题讨论】:
-
不要猜测。 找出问题的原因,找出问题所在,然后编写解决方案来解决该特定问题。线程可能难以推理;确保您精通编码技术,以便安全地使用它们。
标签: multithreading ios8 uicollectionview cloudkit