我刚刚创建了一个UICollectionView
,其中用户可以将手机中的图像添加到应用中的相册功能中。我将图像保存到文档目录中的子目录中,因此可以添加和删除更多图像。但是,当我在集合视图中向上和向下滚动时,它非常迟钝。
如何使滚动变得美观和流畅?
我的代码:前16个图像是预设图像,之后的所有内容都来自文档目录
中的子目录- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Custom" forIndexPath:indexPath];
//Current index number
int index=indexPath.section * noOfSection + indexPath.row;
//Check if its the preset photos
if(index<16){
NSString *name=[recipePhotos objectAtIndex:indexPath.section * noOfSection + indexPath.row];
cell.imageView.image=[UIImage imageNamed:name];
}
//not preset photos, so retrieve the photos the user added
else {
NSData *data= [NSData dataWithContentsOfFile:[recipePhotos objectAtIndex:index]];
UIImage *theImage=[UIImage imageWithData:data];
cell.imageView.image=theImage;
data=nil;
}
return cell;
}
Time Profiler给了我这个
Running Time Self Symbol Name
568.0ms 63.1% 0.0 Main Thread 0x4048
320.0ms 35.5% 0.0 _pthread_start 0x405e
320.0ms 35.5% 0.0 thread_start
320.0ms 35.5% 0.0 _pthread_start
320.0ms 35.5% 0.0 0x1084be960
310.0ms 34.4% 1.0 0x1084be6f0
7.0ms 0.7% 0.0 mach_msg
2.0ms 0.2% 2.0 objc_msgSend
1.0ms 0.1% 1.0 -[NSAutoreleasePool release]
4.0ms 0.4% 0.0 _dispatch_mgr_thread 0x4052
4.0ms 0.4% 0.0 _dispatch_mgr_thread
4.0ms 0.4% 0.0 _dispatch_mgr_invoke
4.0ms 0.4% 4.0 kevent
3.0ms 0.3% 0.0 _dispatch_worker_thread2 0x62b24
3.0ms 0.3% 1.0 start_wqthread
3.0ms 0.3% 0.0 _dispatch_worker_thread2 0x62a84
3.0ms 0.3% 0.0 start_wqthread
3.0ms 0.3% 0.0 _pthread_wqthread
3.0ms 0.3% 0.0 _dispatch_worker_thread2
3.0ms 0.3% 0.0 _dispatch_queue_invoke
3.0ms 0.3% 0.0 _dispatch_queue_drain
3.0ms 0.3% 0.0 _dispatch_client_callout
2.0ms 0.2% 0.0 my_io_execute_passive_block
1.0ms 0.1% 0.0 __86-[NSPersistentUIManager writePublicPlistWithOpenWindowIDs:optionallyWaitingUntilDone:]_block_invoke_0835
1.0ms 0.1% 0.0 -[NSPersistentUIManager writePublicPlistData:]
1.0ms 0.1% 0.0 -[NSURL(NSURLPathUtilities) URLByAppendingPathComponent:]
1.0ms 0.1% 0.0 -[NSURL getResourceValue:forKey:error:]
1.0ms 0.1% 0.0 CFURLCopyResourcePropertyForKey
1.0ms 0.1% 0.0 __block_global_2
1.0ms 0.1% 0.0 -[NSPersistentUIManager writeRecords:withWindowInfos:flushingStaleData:]
1.0ms 0.1% 0.0 _dispatch_call_block_and_release
1.0ms 0.1% 0.0 0x1084b8580
1.0ms 0.1% 0.0 mach_msg_send
1.0ms 0.1% 0.0 mach_msg
1.0ms 0.1% 1.0 mach_msg_trap
1.0ms 0.1% 0.0 _pthread_struct_init 0x62a83
1.0ms 0.1% 0.0 start_wqthread
1.0ms 0.1% 0.0 _pthread_wqthread
1.0ms 0.1% 1.0 _pthread_struct_init
1.0ms 0.1% 0.0 start_wqthread 0x62a7f
答案 0 :(得分:3)
您需要在tableviews中创建一个类似于您需要的方法,您需要重用视图,就像在表视图中重用您的单元格一样。
Ray Wenderlich的一个非常好的教程是:
在第一部分你有基本的,在第二部分他们谈论可重用的观点,你,看看链接:
http://www.raywenderlich.com/22417/beginning-uicollectionview-in-ios-6-part-22
修改强>
加载图像异步的示例:
在您的单元格中创建一个方法loadImageFromFile
,例如,接收您将通过这种方式调整它的路径:
[cell loadImageFromFile:[recipePhotos objectAtIndex:index]];
然后看起来像(也许你需要适应某些东西......):
- (void) loadImageFromFile:(NSString*)path{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
NSData *data= [NSData dataWithContentsOfFile:path];
UIImage *theImage=[UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image=theImage;
});
});
答案 1 :(得分:3)
@ggrana有正确的想法。加载异步肯定会有所帮助。但是,如果每次都从文件加载,那么您仍在进行冗余工作。要考虑的一件事是使用NSCache
来增加异步加载。它基本上是一个NSDictionary
,但它本身就是内存管理,并在存在内存压力时转储数据。
因此,如果你有内存预算,你可以实时制作缩略图(这样你就不必硬编码大小)并将它们存储在缓存中。这样你的图像只会在第一次弹出。每次之后,他们立即加载。
您可以像这样使用它:
@implementation ...
{
NSCache * _johnny; // get it?
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
[cell setImage:nil]; // since they are reused, prevents showing an old image
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage * sticker = [self thumbnailOfSize:CGSizeMake(desiredImageWidth, desiredImageHeight)
forIndex:[indexPath row]];
dispatch_async(dispatch_get_main_queue(), ^{
[cell setImage:sticker];
});
});
}
// load image from disk and cache thumbnail version
- (UIImage*) thumbnailOfSize:(CGSize)size forIndex:(NSInteger)index
{
NSString * cacheKey = [NSString stringWithFormat:@"%@ %d", NSStringFromCGSize(size), index];
UIImage * image = [_johnny objectForKey:cacheKey];
if (!image) {
image = [UIImage imageWithContentsOfFile:_imagePaths[index]];
float desiredWidth = size.width;
float desiredHeight = size.height;
float actualHeight = image.size.height;
float actualWidth = image.size.width;
float imgRatio = actualWidth / actualHeight;
float maxRatio = desiredWidth / desiredHeight;
if(imgRatio != maxRatio) {
if(imgRatio < maxRatio) {
imgRatio = desiredHeight / actualHeight;
actualWidth = imgRatio * actualWidth;
actualHeight = desiredHeight;
} else {
imgRatio = desiredWidth / actualWidth;
actualHeight = imgRatio * actualHeight;
actualWidth = desiredWidth;
}
}
CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
UIGraphicsBeginImageContextWithOptions(rect.size, FALSE, 0); // do right thing for retina
[image drawInRect:rect];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// here's johnny
[_johnny setObject:image forKey:cacheKey];
}
return image;
}
答案 2 :(得分:2)
所以经过一番捣乱,我发现问题是基于几个因素。
One-缩略图的图像太大了,所以我所做的是制作了一个单独的图像阵列,图像尺寸更小,适合细胞。 二 - 在@ggrana的帮助下,打开一个单独的线程加快了进程,使其不那么迟钝。 三 - 我还发现拥有一组图像而不是图像位置更快 - 唯一的问题是它需要更多的内存。