繁体   English   中英

仅在需要时加载图像

[英]Loading images only when needed

当我加载图像以显示到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;
}

显然,您应该及时加载图像。 一个人永远不要保存图像数组(因为它们占用大量内存),而应该保存一个文件名数组。 所以我建议您退休allImagesArray ,而不是定义一个称为filenamesNSMutableArray 然后,您可以动态创建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;
}

当然,这是假定您在viewDidLoad填充了这个NSMutableArrayfilenames

- (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 (以及imageWithContentsOfFile其加载到NSData然后进行imageWithData )如果图像不是很小的话,会有点慢。 在速度较慢的设备上,这可能会导致收集视图的快速滚动稍微停滞。 因此,更好的方法是(a)异步加载图像; (b)使用NSCache优化性能,以便向后滚动。

因此,首先,定义一个缓存:

@property (nonatomic, strong) NSCache *imageCache;

并且,在viewDidLoad实例化它:

self.imageCache = [[NSCache alloc] init];
self.imageCache.name = @"com.company.app.imageCache";

然后, cellForItemAtIndexPath可以(a)从缓存设置图像; (b)如果未找到,则检索图像以适当地异步更新缓存和单元,例如:

- (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;
}

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

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

    [self.imageCache removeAllObjects];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
    cellForItemAtIndexPath:(NSIndexPath *)indexPath

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

viewDidLoad ,我将构建到每个图像的NSString文件路径的数组,然后使用collectionView:cellForItemAtIndexPath:方法从此特定单元格的特定文件路径加载图像。

viewDidLoad您可以仅加载可用图像列表。 因此,删除for循环: for(NSString *str in directoryContent) { ... }在那里循环(编辑:或使其成为简单的for循环,只为包含数据文件的文件名填充数组)

当您在collectionView:cellForItemAtIndexPath:更新特定的collectionviewcell时,只需加载图像(仅1个)。 现在,单元将保存图像数据,而不是视图控制器。 因此,当释放单元时,图像数据也将释放。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM