Ios 使用dispatch\u async控制UICollectionView单元的负载顺序
在我的iOS应用程序中,我有一个UICollectionView,其中每个单元格都包含一个图像。为了避免加载视图花费很长时间,在后台任务中加载图像内容之前,我先加载每个视图,其中包含一个空白图像和标题 我记录了在后台异步任务中加载的图像,看起来屏幕外的单元格图像首先加载,然后是屏幕顶部的单元格。这使得应用程序看起来没有响应,我宁愿让最上面的单元格优先加载: 我还注意到,一旦我开始滚动,单元格中的图像就会突然出现,但它们自己出现的时间要长得多有人能提出控制UICollectionCells加载顺序的策略吗? 这是我的密码: 迭代项目并将ImageView添加到NSMutableArray projectContainers,然后将其转换为单元格Ios 使用dispatch\u async控制UICollectionView单元的负载顺序,ios,objective-c,asynchronous,uicollectionview,Ios,Objective C,Asynchronous,Uicollectionview,在我的iOS应用程序中,我有一个UICollectionView,其中每个单元格都包含一个图像。为了避免加载视图花费很长时间,在后台任务中加载图像内容之前,我先加载每个视图,其中包含一个空白图像和标题 我记录了在后台异步任务中加载的图像,看起来屏幕外的单元格图像首先加载,然后是屏幕顶部的单元格。这使得应用程序看起来没有响应,我宁愿让最上面的单元格优先加载: 我还注意到,一旦我开始滚动,单元格中的图像就会突然出现,但它们自己出现的时间要长得多有人能提出控制UICollectionCells加载顺
for (NSDictionary *currentProject in projects)
{
// data entry
[projectIDs addObject: [currentProject objectForKey:@"id"]];
NSString *projectTitle = [currentProject objectForKey:@"title"];
id delegate = [[UIApplication sharedApplication] delegate];
self.managedObjectContext = [delegate managedObjectContext];
CustomLabel *cellLabel=[[CustomLabel alloc]init];
cellLabel.text = trimmedProjectTitle;
[titles addObject:projectTitle];
CGSize maxLabelSize = CGSizeMake(cellWidth,100);
CustomLabel *titleLabel = [[CustomLabel alloc]init];
// titleLabel styling
titleLabel.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.5f];
titleLabel.textColor =[UIColor whiteColor];
[titleLabel setFont: [UIFont fontWithName: @"HelveticaNeue" size:12]];
titleLabel.text = trimmedProjectTitle;
CGSize expectedLabelSize = [titleLabel.text sizeWithFont:titleLabel.font constrainedToSize:maxLabelSize lineBreakMode:NSLineBreakByWordWrapping];
CGRect labelFrame = (CGRectMake(0, 0, cellWidth, 0));
labelFrame.origin.x = 0;
labelFrame.origin.y = screenWidth/2 - 80 - expectedLabelSize.height;
labelFrame.size.height = expectedLabelSize.height+10;
titleLabel.frame = labelFrame;
// add placeholder image with textlabel
UIImageView *imagePreview = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, cellWidth, cellHeight)];
imagePreview.contentMode= UIViewContentModeScaleAspectFill;
imagePreview.clipsToBounds = YES;
[imagePreview setImage:[UIImage imageNamed:@"blank.png"]];
[imagePreview addSubview:titleLabel];
[imagePreview.subviews[0] setClipsToBounds:YES];
[projectContainers addObject: imagePreview];
// add project thumbnail images in async
dispatch_async(bgQueue, ^{
NSDictionary *imagePath = [currentProject objectForKey:@"image_path"];
NSString *imageUrlString = [imagePath objectForKey: @"preview"];
NSURL *imageUrl = [NSURL URLWithString: imageUrlString];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:(imageUrl)];
UIImage *image = [[UIImage alloc] initWithData:(imageData)];
if(image){
NSLog(@"project with image: %@", projectTitle);
[imagePreview setImage: image];
}
BOOL *builtVal = [[currentProject objectForKey:@"built"]boolValue];
if(builtVal){
UIImageView *builtBanner =[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"built_icon.png"]];
builtBanner.frame = CGRectMake(screenWidth/2 -80, 0, 50, 50);
[imagePreview addSubview: builtBanner];
}
});
}
使用NSMutableArray项目容器渲染单元格:
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// NSLog(@"cellForItemAtIndexPath");
static NSString *identifier = @"NewCell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
if(!reloadProjects){
UIImageView *preview = (UIImageView*) [cell.contentView viewWithTag:[[projectIDs objectAtIndex:indexPath.row]intValue]];
UIImageView *previewContent = [projectContainers objectAtIndex:indexPath.row];
// NSLog(@"fetching image tag %d", [[projectIDs objectAtIndex:indexPath.row]intValue]);
if (!preview)
{
previewContent.tag = [[projectIDs objectAtIndex:indexPath.row]intValue];
// NSLog(@"creating previewContent %li", (long) previewContent.tag);
[cell addSubview: previewContent];
}
[self.collectionView setBackgroundColor:collectionGrey];
cell.contentView.layer.backgroundColor = [UIColor whiteColor].CGColor;
return cell;
}
return cell;
}
编辑:工作解决方案
感谢rob mayoff帮我想出了一个解决方案。这就是我最后所做的,它可以更快地加载图像:
// add project thumbnail images in async
dispatch_async(imageQueue, ^{
NSDictionary *imagePath = [currentProject objectForKey:@"image_path"];
NSString *imageUrlString = [imagePath objectForKey: @"preview"];
NSURL *imageUrl = [NSURL URLWithString: imageUrlString];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:(imageUrl)];
UIImage *image = [[UIImage alloc] initWithData:(imageData)];
if(image){
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"project with image: %@", projectTitle);
[imagePreview setImage: image];
});
}
BOOL *builtVal = [[currentProject objectForKey:@"built"]boolValue];
if(builtVal){
UIImageView *builtBanner =[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"built_icon.png"]];
builtBanner.frame = CGRectMake(screenWidth/2 -80, 0, 50, 50);
dispatch_async(dispatch_get_main_queue(), ^{
[imagePreview addSubview: builtBanner];
});
}
});
在你的代码中有几点需要改进,但你的主要抱怨(“一旦我开始滚动,单元格中的图像突然开始出现,但它们自己出现的时间要长得多”)是因为你违反了命令: 你只能进入 您的视图层次结构 从主线程开始。 看看你的代码:
dispatch_async(bgQueue, ^{
...
[imagePreview addSubview: builtBanner];
您正在从后台线程操作视图层次结构。这是不允许的。例如,请参见的底部注释或
您需要调度回主线程以更新视图层次结构
看电视。它深入地讨论了如何高效地完成你想做的事情。另请参见。感谢您的帮助,并为我指明了正确的方向。我会研究你的建议,看看我是否能解决我的问题!