在下面的代码中,collectionVIEw将平滑滚动,但有时如果我滚动得非常快,则会显示一个不正确的图像,然后在滚动减速时更改为正确的图像.为什么不将cell.cellImage.image设置为nil修复此问题?
- (UICollectionVIEwCell *)collectionVIEw:(UICollectionVIEw *)collectionVIEw cellForItemAtIndexPath:(NSIndexPath *)indexPath{ CustomTabbarCell *cell = [collectionVIEw dequeueReusableCellWithReuseIDentifIEr:@"CustomTabbarCell" forIndexPath:indexPath]; cell.cellimage.image = nil; dispatch_queue_t queue = dispatch_get_global_queue(disPATCH_QUEUE_PRIORITY_HIGH,0ul); dispatch_async(queue,^{ cell.cellimage.image = nil; UIImage *test = [self.optionArray objectAtIndex:indexPath.row]; UIImage *localimage2 = [self imageWithImage:test scaledToSize:CGSizeMake(test.size.wIDth/5,test.size.height/5)]; dispatch_sync(dispatch_get_main_queue(),^{ cell.cellimage.image = localimage2 cell.cellTextLabel.text = @""; [cell setNeedsLayout]; }); }); } return cell; }- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize { UIGraphicsBeginImageContextWithOptions(newSize,NO,0.0); [image drawInRect:CGRectMake(0,newSize.wIDth,newSize.height)]; UIImage *newImage = UIGraphicsGetimageFromCurrentimageContext(); UIGraphicsEndImageContext(); return newImage;}
编辑:
我添加了另一个async来缓存第一个和nil并初始化了cell.image.我在初始快速向下滚动时遇到了同样的问题.然而,在卷轴上,它现在完美无瑕.
我补充说:
-(voID)createDictionary{ for (UIImage *test in self.optionArray) { UIImage *shownImage = [self imageWithImage:test scaledToSize:CGSizeMake(test.size.wIDth/5,test.size.height/5)]; [localimageDict setobject:shownImage forKey:[NSNumber numberWithInt:[self.optionArray indexOfObject:test]]]; }}- (voID)vIEwDIDLoad{ [super vIEwDIDLoad]; if (!localimageDict) { localimageDict = [[NSMutableDictionary alloc]initWithCapacity:self.optionArray.count]; } else { [localimageDict removeAllObjects]; } dispatch_queue_t queue = dispatch_get_global_queue(disPATCH_QUEUE_PRIORITY_HIGH,0ul); dispatch_async(queue,^{ [self createDictionary]; });}- (UICollectionVIEwCell *)collectionVIEw:(UICollectionVIEw *)collectionVIEw cellForItemAtIndexPath:(NSIndexPath *)indexPath{ CustomTabbarCell *cell = [collectionVIEw dequeueReusableCellWithReuseIDentifIEr:@"CustomTabbarCell" forIndexPath:indexPath]; cell.cellimage.image = nil; cell.cellimage.image = [[UIImage alloc]init]; if ([localimageDict objectForKey:[NSNumber numberWithInt:indexPath.row]]) { cell.cellimage.image = [localimageDict objectForKey:[NSNumber numberWithInt:indexPath.row]]; cell.cellTextLabel.text = @""; } else { cell.cellimage.image = nil; cell.cellimage.image = [[UIImage alloc]init]; dispatch_queue_t queue = dispatch_get_global_queue(disPATCH_QUEUE_PRIORITY_HIGH,0ul); dispatch_async(queue,^{ UIImage *test = [self.optionArray objectAtIndex:indexPath.row]; UIImage *shownImage = [self imageWithImage:test scaledToSize:CGSizeMake(test.size.wIDth/5,test.size.height/5)]; [localimageDict setobject:shownImage forKey:[NSNumber numberWithInt:indexPath.row]]; dispatch_sync(dispatch_get_main_queue(),^{ cell.cellimage.image = shownImage; cell.cellTextLabel.text = @""; [cell setNeedsLayout]; }); }); }}return cell;解决方法 仔细看看你的代码示例,我可以看到你的内存问题的根源.跳出来的最重要的问题是您似乎将所有图像保存在一个数组中.这需要非常大的内存(我推断你需要调整它们必须大的图像).
要减少应用程序的占用空间,您不应该维护一组UIImage对象.相反,只需维护一个URL或路径到您的图像,然后只在UI需要时动态创建UIImage对象(一个称为延迟加载的过程).一旦图像离开屏幕,就可以释放它(UICollectionVIEw,就像UItableVIEw为你做的很多清理工作一样,只要你不保持对图像的强引用).
应用程序通常只应维护当前可见图像的UIImage对象.您可能出于性能原因缓存这些已调整大小的图像(例如,使用NSCache),但是当内存不足时,将自动清除缓存.
好的是你显然已经精通异步处理.无论如何,实现可能如下所示:
- (UICollectionVIEwCell *)collectionVIEw:(UICollectionVIEw *)collectionVIEw cellForItemAtIndexPath:(NSIndexPath *)indexPath{ CustomTabbarCell *cell = [collectionVIEw dequeueReusableCellWithReuseIDentifIEr:@"CustomTabbarCell" forIndexPath:indexPath]; Nsstring *filename = [self.filenameArray objectAtIndex:indexPath.row]; // I always use indexPath.item,but if row works,that's great UIImage *image = [self.thumbnailCache objectForKey:filename]; // you can key this on whatever you want,but the filename works cell.cellimage.image = image; // this will load cached image if found,or `nil` it if not found if (image == nil) // we only need to retrIEve image if not found in our cache { dispatch_queue_t queue = dispatch_get_global_queue(disPATCH_QUEUE_PRIORITY_HIGH,^{ UIImage *test = [UIImage imageWithContentsOffile:filename]; // load the image here,Now that we kNow we need it if (!test) { NSLog(@"%s: unable to load image",__FUNCTION__); return; } UIImage *localimage2 = [self imageWithImage:test scaledToSize:CGSizeMake(test.size.wIDth/5,test.size.height/5)]; if (!localimage2) { NSLog(@"%s: unable to convert image",__FUNCTION__); return; } [self.thumbnailCache setobject:localimage2 forKey:filename]; // save the image to the cache dispatch_async(dispatch_get_main_queue(),^{ // async is fine; no need to keep this background operation alive,waiting for the main queue to respond // see if the cell for this indexPath is still onscreen; probably is,but just in case CustomTabbarCell *updateCell = (ID)[collectionVIEw cellForItemAtIndexPath:indexPath]; if (updateCell) { updateCell.cellimage.image = localimage2 updateCell.cellTextLabel.text = @""; [updateCell setNeedsLayout]; } }); }); } return cell;}
这假定您定义了thumbnailCache的类属性,它是对您将在vIEwDIDLoad或其中任何位置初始化的NSCache的强引用.缓存是一种充分利用两个世界的方法,在内存中加载图像以获得最佳性能,但是当您遇到内存压力时它将被释放.
显然,我很乐意假设“哦,只需用一系列图像文件名替换你的图像阵列”,我知道你可能需要进入代码的一些不同部分才能使它工作,但是这个毫无疑问是你的记忆消耗的来源.很明显,你总是会遇到其他内存问题(保留周期等),但在你发布的代码片段中没有类似内容.
总结以上是内存溢出为你收集整理的iphone – UICollectionView Cell Image随着GCD进入视图而改变全部内容,希望文章能够帮你解决iphone – UICollectionView Cell Image随着GCD进入视图而改变所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)