早上好,
我第一次使用 UICollectionView 来显示来自用户的图片(比如Facebook个人资料),此刻我可以很好地展示图片,但我遇到了一些问题:
1-当我访问我的个人资料时,由于加载了5张图片,该应用会冻结2-3分钟。
2-当我正在浏览 UICollectionView 时,当应用再次加载屏幕外的图像时,它会冻结。
为了在加载用户图片时不冻结应用,我需要做些什么?而我必须做什么才能在没有冻结的情况下浏览CollectionView?也许我需要一个缓存系统?
这是我的代码:
ProfileViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor: [self colorWithHexString:@"FFFFFF"]];
self.profileimage.layer.cornerRadius = self.profileimage.frame.size.width / 2;
self.profileimage.clipsToBounds = YES;
self.profileimage.layer.borderWidth = 1.0f;
self.profileimage.layer.borderColor = [UIColor whiteColor].CGColor;
[self fetchJson];
[self fetchImages];
self.oneCollectionView.dataSource = self;
self.oneCollectionView.delegate = self;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 1;
}
-(NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _carImages.count;
}
// COLLECTION VIEW
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:@"MyCell"
forIndexPath:indexPath];
NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:@"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * images = [UIImage imageWithData:imageData];
myCell.imageview.image = images;
return myCell;
}
-(void)fetchImages {
self.carImages = [[NSMutableArray alloc] init];
NSString *usersPassword = [SSKeychain passwordForService:@"login" account:@"account"];
NSString * urlString = [NSString stringWithFormat:@"http://mywebsite.com/posts.php?usersPassword=%@",usersPassword];
NSURL * url = [NSURL URLWithString:urlString];
NSData * data = [NSData dataWithContentsOfURL:url];
NSError *error;
[_jsonArray removeAllObjects];
_jsonArray = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
for(int i=0;i<_jsonArray.count;i++)
{
NSDictionary * jsonObject = [_jsonArray objectAtIndex:i];
NSString* imagen = [jsonObject objectForKey:@"imagen"];
[_carImages addObject:imagen];
}
}
提前致谢。
答案 0 :(得分:1)
异步下载图像,dataWithContentsOfURL
是同步方法,它将阻止当前线程,直到下载完成。您可以使用SDWebImage等库自动为您处理下载,也可以使用NSURLSessionDownloadTask
下载图像。
- (void)fetchImages {
self.carImages = [[NSMutableArray alloc] init];
NSString *usersPassword = [SSKeychain passwordForService:@"login" account:@"account"];
NSString * urlString = [NSString stringWithFormat:@"http://mywebsite.com/posts.php?usersPassword=%@",usersPassword];
NSURL * url = [NSURL URLWithString:urlString];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
[self.jsonArray removeAllObjects];
self.jsonArray = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
for(int i=0;i<_jsonArray.count;i++)
{
NSDictionary * jsonObject = self.jsonArray[i];
NSString* imagen = jsonObject[@"imagen"];
[self.carImages addObject:imagen];
}
}
}];
[dataTask resume];
}
// COLLECTION VIEW
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:@"MyCell"
forIndexPath:indexPath];
NSString *data = [[self.jsonArray objectAtIndex:indexPath.row] valueForKey:@"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
NSURLSessionDownloadTask *imageDownloadTask = [[NSURLSession sharedSession]
downloadTaskWithURL:imageURL completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
UIImage *image = [UIImage imageWithData:
[NSData dataWithContentsOfURL:location]];
myCell.imageview.image = image;
}];
[imageDownloadTask resume];
return myCell;
}
答案 1 :(得分:1)
导入UIImageView+AFNetworking.h
并在cellForItemAtIndexPath
方法
[imageView setImageWithURL:[NSURL URLWithString:@"https://lh6.googleusercontent.com/-B8kSXtoaQDo/VGTVlXyIXpI/AAAAAAAAJ_M/USh6SgvMemw/w1024-h1024/IMG_20141112_103152.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];
它肯定会加速加载和滚动collectionView
答案 2 :(得分:0)
尝试为集合视图注册Nib
在viewController的viewDidLoad()
方法中编写以下代码:
UINib *nib = [UINib nibWithNibName:@"MyCollectionCell" bundle: nil];
[self.collectionView registerNib:nib forCellWithReuseIdentifier:@"Cell"];
我认为你必须在集合视图中使用https://github.com/nicklockwood/AsyncImageView来加载图像。
对于Storyboard,您必须看到本教程:http://www.appcoda.com/ios-programming-uicollectionview-tutorial/这将为您提供更多帮助。
谢谢!
答案 3 :(得分:0)
对于第一个问题,答案就在这行代码中:
NSData * data = [NSData dataWithContentsOfURL:url];
请勿使用此同步方法来请求基于网络的网址。对于 基于网络的URL,此方法可以阻止当前线程为数十 慢速网络上的秒数,导致用户体验不佳,以及 在iOS中,可能会导致您的应用被终止。
作为替代方案,您可以使用NSURLSessionDataTask
下载数据(请参阅Apple Reference)
<强> - 编辑强>
在ProfileViewController.h中添加以下两个属性:
@property (nonatomic, strong) NSURLSessionConfiguration *sessionConfig;
@property (nonatomic, strong) NSURLSession *session;
然后,在- viewDidLoad
初始化它们:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view
self.sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfig];
//Other stuff...
}
最后,在ProfileViewController.m
中-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:@"MyCell"
forIndexPath:indexPath];
NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:@"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
NSURLSessionDownloadTask *imageDownloadTask = [self.session dataTaskWithURL:imageURL
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"ERROR: %@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode == 200) {
UIImage *image = [UIImage imageWithData:data];
myCell.imageview.alpha = 0.0f;
myCell.imageview.image = image;
[UIView animateWithDuration:0.45 animations:^{
myCell.imageview.alpha = 1.0f;
});
} else {
NSLog(@"Couldn't load image at URL: %@", imageURL);
NSLog(@"HTTP %d", (int)httpResponse.statusCode);
}
}
}];
[imageDownloadTask resume];
return myCell;
}
我希望这可以帮到你。
- 编辑2 对于未来的读者,我根据@ suhit的回答(对他来说+1)稍微重构了我的代码
答案 4 :(得分:0)
您可以使用调度程序为下载图像创建异步操作。这将解决您遇到的两个问题:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imgData = [NSData dataWithContentsOfURL:YOUR_IMAGE_URL];
UIImage *img = [UIImage imageWithData:imgData];
[YOUR_IMAGE_VIEW_OUTLET performSelectorOnMainThread:@selector(setImage:) withObject:img waitUntilDone:YES];
});
这些是您需要更改的代码段:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:@"MyCell"
forIndexPath:indexPath];
NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:@"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL: imageURL];
UIImage *img = [UIImage imageWithData:imageData];
[myCell.imageview performSelectorOnMainThread:@selector(setImage:) withObject:img waitUntilDone:YES];
});
return myCell;
}