仅在需要时加载图像

时间:2013-11-17 15:22:47

标签: ios image memory load uicollectionview

当我加载要显示给UICollectionView的图像时,我会像这样加载数组中的所有图像

- (void)viewDidLoad
{
    allImagesArray = [[NSMutableArray alloc] init];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *location=@"Others";
    NSString *fPath = [documentsDirectory stringByAppendingPathComponent:location];
    NSArray *directoryContent = [[NSFileManager defaultManager] directoryContentsAtPath: fPath];
    collectionOthers.delegate =self;
    collectionOthers.dataSource=self;
    for(NSString *str in directoryContent)
    {
        NSString *finalFilePath = [fPath stringByAppendingPathComponent:str];
        NSData *data = [NSData dataWithContentsOfFile:finalFilePath];
        if(data)
        {
            UIImage *image = [UIImage imageWithData:data];
            [allImagesArray addObject:image];
            NSLog(@"array:%@",[allImagesArray description]);
            image = nil;

        }
        finalFilePath=nil;
        data=nil;
    }

    paths= nil;
    documentsDirectory= nil;
    location= nil;
    fPath= nil;
    directoryContent = nil;
}

这是我的应用中最大的问题,因为它使用了这么多内存。这是因为图像的数量和大小,这可能只占用内存。我只想在需要时加载图像,并在不再需要时丢弃它们。但是我不知道在哪里以及如何更改我的代码以便它会这样。我这样做了三个月左右,我真的需要帮助 的更新
这是我特定部分的代码

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *reuseID = @"ReuseID";
    OthersCell *mycell = (OthersCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseID forIndexPath:indexPath];
    UIImageView *imageInCell = (UIImageView*)[mycell viewWithTag:1];
    imageInCell.image = [allImagesArray objectAtIndex:indexPath.row];
    NSLog(@"a");
    return mycell;
}

3 个答案:

答案 0 :(得分:1)

显然,您应该及时加载图像。一个人永远不应该拥有一个图像数组(因为它们会占用大量内存),而只是拥有一个文件名数组。因此,我建议您退出allImagesArray,而是定义一个名为NSMutableArray的{​​{1}}。然后,您可以动态创建filenames个对象:

UIImage

当然,假设您在- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"Cell"; OthersCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; UIImageView *imageInCell = (UIImageView*)[cell viewWithTag:1]; imageInCell.image = [UIImage imageWithContentsOfFile:filenames[indexPath.item]]; return cell; } 中填充了此NSMutableArray filenames}:

viewDidLoad

这有一个问题,因为- (void)viewDidLoad { filenames = [[NSMutableArray alloc] init]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *location=@"Others"; NSString *fPath = [documentsDirectory stringByAppendingPathComponent:location]; NSArray *directoryContent = [[NSFileManager defaultManager] directoryContentsAtPath: fPath]; collectionOthers.delegate =self; collectionOthers.dataSource=self; for(NSString *str in directoryContent) { NSString *finalFilePath = [fPath stringByAppendingPathComponent:str]; [filenames addObject:fileFilePath]; } } (以及首先将它加载到imageWithContentsOfFile然后再加载NSData)如果图像不是很小的话会有点慢。在较慢的设备上,这可能会导致集合视图的快速滚动的轻微卡顿。因此,更好的方法是(a)异步加载图像; (b)使用imageWithData来优化向后滚动时的效果。

首先,定义一个缓存:

NSCache

并在@property (nonatomic, strong) NSCache *imageCache;

中实例化
viewDidLoad

然后,self.imageCache = [[NSCache alloc] init]; self.imageCache.name = @"com.company.app.imageCache"; 可以(a)从缓存中设置图像; (b)如果没有找到,则检索图像异步更新缓存和单元格,例如:

cellForItemAtIndexPath

显然,如果收到内存警告,请确保清除缓存(在iOS 7中,缓存并不总是像以前那样在压力下自动清除自己):

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"Cell";
    OthersCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
    UIImageView *imageInCell = (UIImageView*)[cell viewWithTag:1];

    NSString *cacheKey = filenames[indexPath.item];
    imageInCell.image = [self.imageCache objectForKey:cacheKey];

    if (imageInCell.image == nil) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            UIImage *image = [UIImage imageWithContentsOfFile:filenames[indexPath.item]];
            if (image) {
                [self.imageCache setObject:image forKey:cacheKey];
                dispatch_async(dispatch_get_main_queue(), ^{
                    OthersCell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];
                    UIImageView *imageInCell = (UIImageView*)[updateCell viewWithTag:1];
                    imageInCell.image = image;
                });
            }
        });
    }

    return cell;
}

答案 1 :(得分:0)

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
    cellForItemAtIndexPath:(NSIndexPath *)indexPath

这是您应该加载图像的方法。

viewDidLoad中,我将为每个图像构建NSString个文件路径数组,然后我使用collectionView:cellForItemAtIndexPath:方法从特定文件路径加载图像这个特殊的细胞。

答案 2 :(得分:0)

viewDidLoad中您只需加载可用图片列表即可。因此,删除for循环:for(NSString *str in directoryContent) { ... }循环(编辑:或使其成为一个简单的for循环,只是为具有数据的文件的文件名填充数组

更新collectionView:cellForItemAtIndexPath:中的特定集合视图单元时,只需加载图像(仅1)。单元格现在将保存图像数据而不是视图控制器。因此,当细胞被释放时,图像数据也是如此。