我正在使用集合视图并尝试从同步加载数据转换为异步加载它。
我知道以下内容当前有效(加载需要一段时间,但所有单元格在完成时都会正确显示):
// load projectData in main thread
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
[self performSelectorOnMainThread:@selector(fetchProjects:)withObject:projectData waitUntilDone:YES];
我重写了它以异步方式完成所有事情:
// load project data asynchronously
dispatch_async(bgQueue, ^{
UIView *loadingAnimation = loadingCircle;
loadingAnimation.tag = 15;
[self.collectionView addSubview:loadingAnimation];
[loadingCircle startAnimating];
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
[self performSelector:@selector(fetchProjects:) withObject:projectData];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"finished with loading projects");
UIView *viewToRemove = [self.view viewWithTag:15];
[viewToRemove removeFromSuperview];
[self.collectionView reloadData];
});
});
当我在异步加载数据后运行应用程序时,视图显示为空(单元格没有内容),但是当我滚动时,一些单元格开始出现。
除了reloadData之外还有什么我需要调用才能使我的集合单元格正确显示?
这是我的fetchProjects:
// get JSON data of projects
- (void)fetchProjects:(NSData *)responseData {
NSError * error;
NSDictionary * json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error]; // get dictionary from json data
NSDictionary * data = [json objectForKey:@"data"]; // get data in array
NSArray * projects = [data objectForKey:@"projects"];
NSDictionary * mostRecentProject = [projects objectAtIndex:0];
mostRecentProjectID = [mostRecentProject objectForKey:@"id"];
for (NSDictionary *currentProject in projects)
{
[projectIDs addObject: [currentProject objectForKey:@"id"]];
NSString *projectTitle = [currentProject objectForKey:@"title"];
NSString *trimmedProjectTitle = [projectTitle stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
id delegate = [[UIApplication sharedApplication] delegate];
self.managedObjectContext = [delegate managedObjectContext];
Project *newProject = (Project *) [NSEntityDescription insertNewObjectForEntityForName:@"Project" inManagedObjectContext:[self managedObjectContext]];
CustomLabel *cellLabel=[[CustomLabel alloc]init];
cellLabel.text = trimmedProjectTitle;
NSLog(@"fetchprojects:%@",projectTitle);
[titles addObject:projectTitle];
CGSize maxLabelSize = CGSizeMake(screenWidth/2 - 30,100);
CustomLabel *titleLabel = [[CustomLabel alloc]init];
[titleLabel setNumberOfLines:0];
titleLabel.text = projectTitle;
CGSize expectedLabelSize = [titleLabel.text sizeWithFont:titleLabel.font constrainedToSize:maxLabelSize lineBreakMode:NSLineBreakByWordWrapping];
CGRect labelFrame = (CGRectMake(0, 0, screenWidth/2 - 30, 0));
labelFrame.origin.x = 0;
labelFrame.origin.y = screenWidth/2 - 70 - expectedLabelSize.height;
labelFrame.size.height = expectedLabelSize.height;
titleLabel.frame = labelFrame;
titleLabel.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.5f];
titleLabel.textColor =[UIColor whiteColor];
[titleLabel setFont: [UIFont fontWithName: @"HelveticaNeue" size:12]];
//NSLog(@"%@", titleLabel.text);
UIImageView *imagePreview = [[UIImageView alloc] initWithFrame:CGRectMake(7.5, 10, screenWidth/2 -30, screenWidth/2 -70)];
imagePreview.contentMode= UIViewContentModeScaleAspectFill;
imagePreview.clipsToBounds = YES;
[imagePreview setImage:[UIImage imageNamed:@"blank.png"]];
[imagePreview addSubview:titleLabel];
[imagePreview.subviews[0] setClipsToBounds:YES];
[projectContainers addObject: imagePreview];
}
}
答案 0 :(得分:2)
你在后台线程上做了很多UI工作,你真的不应该这样做。从我所看到的,真正需要在后台线程上运行的唯一一行就是这一行:
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
其余部分看起来像处理设置和显示你的UI和一些CoreData的东西; 所有这些都需要在主线程上运行。最简单的方法是保持一切按正确的顺序运行:
// NOTE: If you're sure you're already on the main thread here, you don't need the dispatch, but it's not going to hurt to leave it in.
dispatch_async(dispatch_get_main_queue(), ^{
UIView *loadingAnimation = loadingCircle;
loadingAnimation.tag = 15;
[self.collectionView addSubview:loadingAnimation];
[loadingCircle startAnimating];
});
dispatch_async(bgQueue, ^{
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
dispatch_async(dispatch_get_main_queue(), ^{
[self fetchProjects:projectData];
NSLog(@"finished with loading projects");
UIView *viewToRemove = [self.view viewWithTag:15];
[viewToRemove removeFromSuperview];
[self.collectionView reloadData];
});
});
注意:我还将[self performSelector:@selector(fetchProjects:) withObject:projectData]
更改为[self fetchProjects:projectData]
;你真的不需要经过那里的performSelector:
。