Asynchronously set images in tableview

前端 未结 4 1136
鱼传尺愫
鱼传尺愫 2020-12-22 12:27

I have a TableView using custom cells. I initially was setting grabbing an image from a URL in the cellForRowAtIndexPath method

- (         


        
相关标签:
4条回答
  • 2020-12-22 12:39
    1. Create UIImageView Class File (i named it to MJTableImageView).

    in MJTableImageView.h File

        @interface MJTableImageView : UIImageView< NSURLConnectionDelegate, NSURLConnectionDataDelegate >
    
        {
        NSMutableData *imageData ;
        long long expectedLength;
        NSURLConnection *currentConnection;
        NSString *File_name;
    
        }
        @property(nonatomic,readonly)UIActivityIndicatorView *loadingIndicator;
        @property(nonatomic)BOOL showLoadingIndicatorWhileLoading;
    
        -(void)setImageUrl:(NSURL *)imageUrl fileName:(NSString *)name;
    
        @end
    

    in MJTableImageView.m File

    -(void)setImageUrl:(NSURL *)imageUrl fileName:(NSString *)name
    {
        // discard the previous connection
        if(currentConnection)
        {
            [currentConnection cancel];
        }
    
        File_name = name;
    
        //reset current image
        self.image = nil;
    
    
    //    if(_showLoadingIndicatorWhileLoading)
    //    {
            //show the loading indicator
    
            if(!_loadingIndicator)
            {
                CGFloat width = self.bounds.size.width*0.5;
    
                _loadingIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake((self.bounds.size.width-width)/2, (self.bounds.size.height-width)/2, 25.0 , 25.0)];
                _loadingIndicator.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
                _loadingIndicator.layer.cornerRadius = width*0.1;
            }
            [self startLoadingIndicator];
    //    }
    
        // initialize the placeholder data
        imageData = [NSMutableData data];
    
    
        // start the connection
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:imageUrl];
        request.cachePolicy = NSURLRequestUseProtocolCachePolicy;
    
        currentConnection = [NSURLConnection connectionWithRequest:request delegate:self];
    
    
    
    }
    -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        //if the image view is reused in a table view for example to load another image  previous image is discarded
        if(connection != currentConnection)
        {
            [connection cancel];
            [self cleanUp];
            return;
        }
    
        // append new Data
        [imageData appendData:data];
    
    
    
        // show the partially loaded image
        self.image = [UIImage imageWithData:imageData];
    }
    -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        expectedLength = response.expectedContentLength;
    }
    -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
        // clean up
        [self cleanUp];
    
    }
    -(void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        // show the full image
        self.image = [UIImage imageWithData:imageData];
    
        NSString *filename = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@", File_name];
        NSData *data = UIImagePNGRepresentation([UIImage imageWithData:imageData]);
        [data writeToFile:filename atomically:YES];
    
        // clean up
        [self cleanUp];
    }
    -(void)cleanUp
    {
        // clean up
        imageData = nil;
        [self stopLoadingIndicator];
    }
    -(void)startLoadingIndicator
    {
        if(!_loadingIndicator.superview)
        {
            [self addSubview:_loadingIndicator];
        }
        [_loadingIndicator startAnimating];
    }
    -(void)stopLoadingIndicator
    {
        if(_loadingIndicator.superview)
        {
            [_loadingIndicator removeFromSuperview];
        }
        [_loadingIndicator stopAnimating];
    }
    

    I am using StoryBoard so i add ImageClass(MJTableImageView) file to UItableviewcell ImageView and set tag number to it.

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        NSDictionary *dict = [self.arr objectAtIndex:indexPath.row];
    
        UITableViewCell *cell = [self.MJTableView dequeueReusableCellWithIdentifier:@"MJImageCell"];
        if(cell == nil)
        {
    
        }
        UILabel *appName = (UILabel*)[cell.contentView viewWithTag:2];
        appName.text = [dict valueForKey:@"trackName"];
    
        MJTableImageView *imageview = (MJTableImageView *)[cell.contentView viewWithTag:1];
    
        NSString *url = [dict valueForKey:@"artworkUrl60"];
    
        NSString *filename = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@",[dict valueForKey:@"trackName"] ];
        NSData *data = [NSData dataWithContentsOfFile:filename];
        if(data)
        {
            imageview.image = [UIImage imageWithData:data];
        }
        else
        {
            [imageview setImageUrl:[NSURL URLWithString:url] fileName:[dict valueForKey:@"trackName"]];
        }
        return  cell;
    }
    

    For More details see Github Project MJTableImageSwift it is in Swift.

    0 讨论(0)
  • 2020-12-22 12:48

    Step 1: Have a cache containing images. Either just in memory, better on disk.

    Step 2: When you need an image, call a method which either returns an image from the cache, or returns a default image and starts a download.

    Step 3: When a download finishes, add the image to the cache. Then find out which rows need the image. Reload all the rows that reload the image.

    The download should be done asynchronously using GCD. I would really recommend that you add the download code into a separate, reusable method so that you can handle download errors. Even if you don't do it now, you will do it later.

    0 讨论(0)
  • 2020-12-22 12:57

    Use this code inside your tableviews cellforindexpath

     NSURLRequest *req =[[NSURLRequest alloc]initWithURL:[NSURL URLWithString:@"yourimageurl.com"]];
    
    [NSURLConnection sendAsynchronousRequest:req queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        if(!error){
            UIImage *image =[UIImage imageWithData:data];
            cell.thumbnailImageView.image = image;
        }
         else{
                //error
       }
    
    
    }];
    
    0 讨论(0)
  • 2020-12-22 13:02

    dataWithContentsOfURL is a synchronous method rather than asynchronous,as Apple Documents described.

    This method is ideal for converting data:// URLs to NSData objects, and can also be used for reading short files synchronously. If you need to read potentially large files, use inputStreamWithURL: to open a stream, then read the file a piece at a time.

    In order to asynchronously load image,especially in tableViewCell,try use 3rd part Library SDWebImage

    0 讨论(0)
提交回复
热议问题