xcode async tableview load image move listview images gone

814 views Asked by At

We want to download image and data async to our tableview and we want to cache it not to download it again. We found a code for caching.Here is our code. It works asynchronously but when we scroll table view, images gone and come back(we cant see image for a while). Sometimes wrong image come to wrong cell. What might be the reasons and how can we solve it ?

 NSURL *imageURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@",[userInfo[0] serverUrl],[estateList[indexPath.row] imgUrl]]];

    NSString *key = [imageURL absoluteString];
    NSData *data = [FTWCache objectForKey:key];
    if (data) {
        UIImage *image = [UIImage imageWithData:data];
        cell.imageView.image = image;
    } else {
        cell.imageView.image = [UIImage imageNamed:@"yukleniyor"];
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
        dispatch_async(queue, ^{
            NSData *data = [NSData dataWithContentsOfURL:imageURL];
            [FTWCache setObject:data forKey:key];
            UIImage *image = [UIImage imageWithData:data];
            dispatch_async(dispatch_get_main_queue(), ^{
                cell.imageView.image = image;
            });
        });
    }

Here is that code we found for caching

Header is like this

#import <Foundation/Foundation.h>

@interface FTWCache : NSObject

+ (void) resetCache;

+ (void) setObject:(NSData*)data forKey:(NSString*)key;
+ (id) objectForKey:(NSString*)key;

@end

And .m file is like this

#import "FTWCache.h"

static NSTimeInterval cacheTime =  (double)604800;

@implementation FTWCache

+ (void) resetCache {
    [[NSFileManager defaultManager] removeItemAtPath:[FTWCache cacheDirectory] error:nil];
}

+ (NSString*) cacheDirectory {
    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cacheDirectory = [paths objectAtIndex:0];
    cacheDirectory = [cacheDirectory stringByAppendingPathComponent:@"FTWCaches"];
    return cacheDirectory;
}

+ (NSData*) objectForKey:(NSString*)key {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *filename = [self.cacheDirectory stringByAppendingPathComponent:key];

    if ([fileManager fileExistsAtPath:filename])
    {
        NSDate *modificationDate = [[fileManager attributesOfItemAtPath:filename error:nil] objectForKey:NSFileModificationDate];
        if ([modificationDate timeIntervalSinceNow] > cacheTime) {
            [fileManager removeItemAtPath:filename error:nil];
        } else {
            NSData *data = [NSData dataWithContentsOfFile:filename];
            return data;
        }
    }
    return nil;
}

+ (void) setObject:(NSData*)data forKey:(NSString*)key {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *filename = [self.cacheDirectory stringByAppendingPathComponent:key];

    BOOL isDir = YES;
    if (![fileManager fileExistsAtPath:self.cacheDirectory isDirectory:&isDir]) {
        [fileManager createDirectoryAtPath:self.cacheDirectory withIntermediateDirectories:NO attributes:nil error:nil];
    }

    NSError *error;
    @try {
        [data writeToFile:filename options:NSDataWritingAtomic error:&error];
    }
    @catch (NSException * e) {
        //TODO: error handling maybe
    }
}


@end
1

There are 1 answers

2
Nikita On

Sorry for my previous answer. I will try to explain the problem: We have TableView total number of rows and rows of the reserved area of the display. As a result, images with asynchronous load can not be loaded into their cells (because it is inserted as it downloads from the memory).

The solution is very simple, you must assign each ImageView with key and this key associated with the cells of the table.

I resolve this problem by using code from this git (https://gist.github.com/khanlou/4998479)

There are two files on it

UIImageView+Network.h
UIImageView+Network.m

You must include they in your project, or create own class and paste to it.

This class uses FTW/FTWCache from (https://github.com/FTW/FTWCache/tree/master/FTWCache). So you must add to your project this one too.

After that you must to import

#import "UIImageView+Network.h"

in file which will use asynchronous image loading and caching.

And short part of code with TableView using

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *simpleTableIdentifier = @"MyTableCell";

    MyTableCell *cell = (MyTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil){
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MyTableCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    }
    // construction to call method 
    // [cell.imageView loadImageFromURL:(NSURL*)url placeholderImage:(UIImage*)placeholder cachingKey:(NSString*)key ];

    [cell.thumbnailImageView loadImageFromURL:(NSURL*)url placeholderImage:[UIImage imageNamed:@"no_foto.gif"]  cachingKey:(NSString*)[NSString stringWithFormat:@"%d",indexPath.row]];

    return cell;
}