iOS   发布时间:2022-03-30  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了iphone – UICollectionView Cell Image随着GCD进入视图而改变大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我需要调整大型本地存储的图像(包含在self.optionArray中),然后在collectionView中显示它.如果我只是显示它,iOS会尝试调整图像大小,因为我快速滚动导致与内存相关的崩溃.

在下面的代码中,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(@"@L_772_20@: unable to load image",__FUNCTION__);
                return;
            }

            UIImage *localImage2 = [self imageWithImage:test scaledToSize:CGSizeMake(test.size.width/5,test.size.height/5)];
            if (!localImage2)
            {
                NSLog(@"@L_772_20@: 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进入视图而改变所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。