Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory issue when working with large array of UIImage

I'm storing about 100 UIImage at one single array. I know there is a memory usage issue that eventually crashes the app, specifically on older devices(iPhone 4s). In terms of User Experience storing all the UIImages on DocumentsDirectory - is not an option(takes too long). So i was thinking about "merging" this two methods. Wait until i'll receive a memory usage warning,stop saving images to my array, and then start storing over the disk. I can't find the right way to handle Memory leak/warning/usage call

 override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        print("memory warning")
    }

When i'm testing on real device, it's just crashes - without call the method. Any suggestions?

like image 834
Roi Mulia Avatar asked Nov 09 '22 20:11

Roi Mulia


1 Answers

Try to use image cache library. The comparison of the most popular is here: https://bpoplauschi.wordpress.com/2014/03/21/ios-image-caching-sdwebimage-vs-fastimage/

My experience: SDWebImage is the best for URL-sourced images usually from internet and Haneke is good for ID-based images for example thumbnails generated from video. Both available in CocoaPods.

SDWebImage uses CoreData SQLite DB for URL caching. It hasn't methods for "hand make" images but worldwide popular in ~REST applications downloading images from internet. I'm using it in just published in the AppStore MyHairDressers app. FastCache uses files for URL caching. But it also like SDWebImage not suited to cache "hand make" images. Both well suited for images downloaded by URLs. Haneke can store images by custom IDs not only by URLs. But like FastCache it requires some configuration. Here is code for some configurations:

``

HNKCacheFormat *cacheFormatThumbnail = [[HNKCache sharedCache] formats][CACHE_FORMAT_THUMBNAIL];
        if (cacheFormatThumbnail == nil)
        {
            cacheFormatThumbnail = [[HNKCacheFormat alloc] initWithName:CACHE_FORMAT_THUMBNAIL];
            cacheFormatThumbnail.size = CGSizeMake(100.0f, 56.0f);
            cacheFormatThumbnail.scaleMode = HNKScaleModeAspectFit;
            cacheFormatThumbnail.compressionQuality = 0.5f;
            cacheFormatThumbnail.diskCapacity = 10 * 1024 * 1024; // 10MB
            cacheFormatThumbnail.preloadPolicy = HNKPreloadPolicyLastSession;
            [[HNKCache sharedCache] registerFormat:cacheFormatThumbnail];
        }
        HNKCacheFormat *cacheFormatPhoto = [[HNKCache sharedCache] formats][CACHE_FORMAT_PHOTO];
        if (cacheFormatPhoto == nil)
        {
            cacheFormatPhoto = [[HNKCacheFormat alloc] initWithName:CACHE_FORMAT_PHOTO];
            CGFloat scale = [[UIScreen mainScreen] scale];
            cacheFormatPhoto.size = CGSizeMake(1280.0f * scale, 720.0f * scale);
            cacheFormatPhoto.scaleMode = HNKScaleModeAspectFit;
            cacheFormatPhoto.compressionQuality = 0.5f;
            cacheFormatPhoto.diskCapacity = 50 * 1024 * 1024; // 50MB
            cacheFormatPhoto.preloadPolicy = HNKPreloadPolicyNone;
            [[HNKCache sharedCache] registerFormat:cacheFormatPhoto];
        }

``

and here is example for creating cached images (TableViewCell contains CollectionView with thumbnails):

``

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    VideoCell *cell = (VideoCell *)[super tableView:tableView cellForRowAtIndexPath:indexPath];
    VideoAsset *asset = (VideoAsset *)[self.fetchedResultsController objectAtIndexPath:indexPath];
    if ([asset thumbnails] == 0)
    {
        MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:[cell thumbnails]];
        hud.removeFromSuperViewOnHide = YES;
        [[cell thumbnails] addSubview:hud];
        hud.labelText = NSLocalizedString(@"H11",nil);
        [hud show:YES];
        CGFloat scale = [[UIScreen mainScreen] scale];
        CGSize size = CGSizeMake(100.0f * scale, 56.0f *scale);
        __weak typeof(cell) weakCell = cell;
        [asset generateThumbnails:self->thumbnailsCount offset:self->thumbnailsOffset size:size completion:^(NSArray *thumbnails) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [hud hide:YES];
            });
            if ((thumbnails != nil) && ([thumbnails count] > 0))
            {
                HNKCache *cache = [HNKCache sharedCache];
                NSUInteger n = 0;
                NSUInteger keyHash = [[[asset assetURL] absoluteString] hash];
                for (UIImage *image in thumbnails)
                {
                    [cache setImage:image forKey:[NSString stringWithFormat:@"%lu@%i",(unsigned long)keyHash,(int)(n++)] formatName:CACHE_FORMAT_THUMBNAIL];
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (weakCell != nil)
                        {
                            __strong typeof(cell) strongCell = weakCell;
                            [[strongCell thumbnails] reloadData];
                        }
                    });
formatName:CACHE_FORMAT_PHOTO];
                }
            }
        }];
    }
    return (UITableViewCell *)cell;
}

``

and using (collection view cell of the collection in the table view cell):

``

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    ThumbnailCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
    NSString *key = [NSString stringWithFormat:@"%lu@%i",(unsigned long)[[[(VideoAsset *)self->_selectedObject assetURL] absoluteString] hash],(int)[indexPath item]];
    [cell setKey:key];
    [cell setTag:[indexPath item]];
    __weak typeof(cell) weakCell = cell;
    [[HNKCache sharedCache] fetchImageForKey:key formatName:CACHE_FORMAT_THUMBNAIL success:^(UIImage *image) {
        [[weakCell image] setImage:image];
    } failure:^(NSError *error) {
        if ([[error domain] isEqualToString:HNKErrorDomain] && ([error code] == HNKErrorImageNotFound))
        {
            [[weakCell image] setImage:[UIImage imageNamed:@"movieplaceholder"]];
        }
        else [error reportError];
    }];
    return cell;
}

``

like image 153
Alexey Lobanov Avatar answered Dec 01 '22 09:12

Alexey Lobanov