简体   繁体   中英

cells in tableview not scrolling smoothly

I am almost done coding my app, but I still have a problem that I couldn't solve for weeks...I browsed on this site and other websites on the same issue, but I couldn't find a way to solve it. I have a table view with cells (like Instagram) with images downloaded from the server. My problem is when I scroll the table view, it's not smooth and it blinks.

To construct the table view, I do the following:

-the header views and the cells are subclassed. -I download all the images async and cache them afterwards (about 25Ko each) in the tmp folder of my app. -each image downloaded has the same frame as the UIImageView in which it should be placed. -I tried to save the images in png and jpeg format, but the problem remains.

I did another test where instead of putting the downloaded images inside the cells, I put an image inside my app (with any scaling). In that case, the table view scrolls smoothly.

So I suspect maybe the problem is with the way I cache the images and get them from the cache. But even in this case, I tried to cache the images using NSCache and a temporary folder, but no result...

Here is my code:

-(void)CacheTheImageDownloaded: (NSData *)TheImageData : (NSString*)PathOfImage{

   NSFileHandle *fout;
   [[NSFileManager defaultManager] createFileAtPath:PathOfImage contents:Nil   attributes:Nil];
   fout = [NSFileHandle fileHandleForWritingAtPath:PathOfImage];
   [fout writeData:TheImageData ];
   [fout closeFile];

}


-(UIImage*)GetTheImageFromTemporaryDirectory:(NSString*)ImagePath{
   UIImage *theCachedImage;
   theCachedImage = [UIImage imageWithContentsOfFile:ImagePath];
   return theCachedImage;
}


-(void)GetImageForTheViewedCell: (NSString*) ImageName : (NSString*)TheImageURL :    (NSInteger)therow : (UIImageView*)MyImageView {

  NSString *TheKey = [NSString stringWithFormat:@"%ld", (long)therow];
  NSString *tmpDir = NSTemporaryDirectory();
  NSString *ImageDownloadedTmpDir;
  ImageDownloadedTmpDir = [tmpDir stringByAppendingPathComponent:@"TMPImagesDownloaded"];

  NSMutableString *TheImagePath = [NSMutableString stringWithString:ImageDownloadedTmpDir];
  [TheImagePath appendString:@"/"];
  [TheImagePath appendString:ImageName ];

if ( [self VerifyIfImageIsAlreadyCached:TheImagePath]){
    MyImageView.image = [self GetTheImageFromTemporaryDirectory:TheImagePath];
}
else{
    NSBlockOperation *loadImageIntoCellOp = [[NSBlockOperation alloc] init];
    [loadImageIntoCellOp addExecutionBlock:^(void){
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),  ^{
            NSURL *theURL = [NSURL URLWithString:TheImageURL];
            NSData *data1 = [NSData dataWithContentsOfURL:theURL ];
            NSData *data = UIImagePNGRepresentation([UIImage imageWithData:data1]);
            dispatch_sync(dispatch_get_main_queue(), ^{
                MyImageView.image = [UIImage imageWithData:data];
                NSBlockOperation *ongoingDownloadOperation =       [self.TheImageDownloadOperations objectForKey:TheKey];
                if (ongoingDownloadOperation) {
                    [self.TheImageDownloadOperations removeObjectForKey:TheKey];
                }
                [self CacheTheImageDownloaded:data :TheImagePath];
            });
        });
    }];

    if (TheKey) {
        [self.TheImageDownloadOperations setObject:loadImageIntoCellOp forKey:TheKey];
    }

    if (loadImageIntoCellOp) {
        [self.imageLoadingOperationQueue addOperation:loadImageIntoCellOp];
    }

}


}

I am working on Xcode 5.02.

Thanks for your suggestions!

EDIT

Here is my code for CellForRowAtIndexpath:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {


 static NSString *cellIdentifier = @"myCustomCell";
 MyCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
 if (cell == nil){
     cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
 }
[cell.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

NSInteger row = indexPath.row;
cell.tag = row ;

//The Profile picture
NSString *theurl = self.myProfilePics[row];
NSString *TheImageName = self.TheImageNames[row];
[self GetImageForTheViewedCell:TheImageName:theurl:row: cell.ProfilePicView];  //getting image from the cache or downloaded async
[cell.TheProfilePicButton setBackgroundImage:cell.ProfilePicView.image forState:UIControlStateNormal];
[cell.contentView addSubview: cell.TheProfilePicButton];

//Username:
NSString *myusername = self.Usernames[row];
[cell.UsernameButton setTitle: myusername forState:UIControlStateNormal];
[cell.contentView addSubview:cell.UsernameButton];

//date
NSString *mydate =  self.Dates[row];
[cell.DateLabel setText: mydate];
[cell.contentView addSubview: cell.DateLabel];

return cell;

}

You said that 'I tried to save the images in png and jpeg format'. I suppose, you just "save to cache" the images. And you use UIImagePNGRepresentation in your tableview.

UITableView plays very low performance when you load many images, even if you implement "lazy load".

So, my answer is you should use UIImageJPEGRepresentation in place of UIImagePNGRepresentation .

EDIT

How about using UIGraphicsGetImageFromCurrentImageContext ?

UIImage *image = [UIImage imageWithContentsOfFile:filePath];
CGSize imageSize = image.size;
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
[image drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];

And one more, how NSCache improve performances. Here is an sample

@inteface YourTableViewController ()
@property (nonatomic) NSCache *cache;
@end

@implemetation YourTableViewController

.
.
.

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *CellIdentifier = @"Cell";
    YourCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil)
    {
        cell = [[YourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        cell.yourImageView.frame = CGRectMake((self.frame.size.width - self.rowHeight)*0.5f, 0, self.rowHeight, self.rowHeight);
    }
    [cell.imageView setImage:nil];
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_async(globalQueue, ^(){

        UIImage *image = [self.cache objectForKey:filePath];
        if (image == nil) {
            image = [UIImage imageWithContentsOfFile:filePath];
            CGSize imageSize = image.size;
            UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
            [image drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
            image = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            [self.cache setObject:image forKey:filePath];
        }

        dispatch_async(mainQueue, ^(){
            if ([[tableView indexPathsForVisibleRows] containsObject:indexPath]) {
                YourCell *cell = (YourCell *)[tableView cellForRowAtIndexPath:indexPath];
                if(image) {
                    [cell.yourImageView setImage:image];
                }
            }
        });
    });
    return cell;
}

.
.
.

@end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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