Download image asynchronously

I need to download an image from the Internet and display it in ImageView . I am currently using SDWebImage (this is an asynchronous cache-enabled image downloader with the UIImageView category).

But it crashes when I click the Back and Forward buttons (when I try to repeat viewing over and over again). In any case, this happens very rarely, but I need to get rid of this error. Is there another library (which does not use a private API) that I could use in my project?

+4
source share
8 answers

Yes. You can use another library. I have already implemented this using AsyncImageView , which inherits from UIImageView . What it does is save the images in cache memory, extracted from the URL, and whenever you need to download the image from the same again, it will just load it from the cache, saving a lot of time.

Just follow the link to implement it:

https://github.com/nicklockwood/AsyncImageView#readme

http://www.markj.net/iphone-asynchronous-table-image/

Please see the image showing the technique that I implemented. It allows you to perform other activities while loading images .:

enter image description here

+10
source

NSURLConnection provides asynchronous download and is built into iOS.

+6
source

I think that the error you are describing can happen because when you β€œreturn”, you release some objects that may be delegates to connections that still work. To avoid crashes, you must cancel connections before release or release any object that might be a delegate to a working connection.

Another alternative for downloading async images is http://allseeing-i.com/ASIHTTPRequest/ .

+4
source

I personally use the built-in Grand Central Dispatch feature in iOS to asynchronously download images from the server.

Below is the code that I used to retrieve photos from Flickr in one of my applications.

There is a function in your image / photo class that looks something like this:

 - (void)processImageDataWithBlock:(void (^)(NSData *imageData))processImage { NSString *url = self.imageURL; dispatch_queue_t callerQueue = dispatch_get_current_queue(); dispatch_queue_t downloadQueue = dispatch_queue_create("Photo Downloader", NULL); dispatch_async(downloadQueue, ^{ NSData *imageData = *insert code that fetches photo from server*; dispatch_async(callerQueue, ^{ processImage(imageData); }); }); dispatch_release(downloadQueue); } 

In your photo view controller, you can call this function as follows:

 - (void)viewWillAppear:(BOOL)animated { [spinner startAnimating]; [self.photo processImageDataWithBlock:^(NSData *imageData) { if (self.view.window) { UIImage *image = [UIImage imageWithData:imageData]; imageView.image = image; imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height); scrollView.contentSize = image.size; [spinner stopAnimating]; } }]; } 
+4
source
 //JImage.h #import <Foundation/Foundation.h> @interface JImage : UIImageView { NSURLConnection *connection; NSMutableData* data; UIActivityIndicatorView *ai; } -(void)initWithImageAtURL:(NSURL*)url; @property (nonatomic, retain) NSURLConnection *connection; @property (nonatomic, retain) NSMutableData* data; @property (nonatomic, retain) UIActivityIndicatorView *ai; @end //JImage.m #import "JImage.h" @implementation JImage @synthesize ai,connection, data; -(void)initWithImageAtURL:(NSURL*)url { [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; [self setContentMode:UIViewContentModeScaleToFill]; if (!ai){ [self setAi:[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]]; [ai startAnimating]; [ai setFrame:CGRectMake(27.5, 27.5, 20, 20)]; [ai setColor:[UIColor blackColor]]; [self addSubview:ai]; } NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60]; connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; } - (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData { if (data==nil) data = [[NSMutableData alloc] initWithCapacity:5000]; [data appendData:incrementalData]; NSNumber *resourceLength = [NSNumber numberWithUnsignedInteger:[data length]]; NSLog(@"resourceData length: %d", [resourceLength intValue]); } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"Connection error..."); [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; [ai removeFromSuperview]; } - (void)connectionDidFinishLoading:(NSURLConnection*)theConnection { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; [self setImage:[UIImage imageWithData: data]]; [ai removeFromSuperview]; } @end //Include the definition in your class where you want to use the image -(UIImageView*)downloadImage:(NSURL*)url:(CGRect)frame { JImage *photoImage=[[JImage alloc] init]; photoImage.backgroundColor = [UIColor clearColor]; [photoImage setFrame:frame]; [photoImage setContentMode:UIViewContentModeScaleToFill]; [photoImage initWithImageAtURL:url]; return photoImage; } //How to call the class UIImageView *imagV=[self downloadImage:url :rect]; //you can call the downloadImage function in looping statement and subview the returned imageview. //it will help you in lazy loading of images. //Hope this will help 
+2
source

Give up on EGOImageLoading with huge caching images. It works the same as UIImageView and allows you to download images from HTTP asynchronously, as well as easily integrate

+2
source

I know this is a very old thread, but lately I've had a lot of random crashes with SDWebImage, so I had to implement my own lazy loading and caching mechanism. It works very well, I just did not test it in cases of heavy load. So, here are the .h and .m files, and then the way I use it:

 // UIImageView+CustomCache.h @interface UIImageView(CustomCache) -(void)startAsyncDownload:(UIImage*)placeHolderImage imageUrlString:(NSString*)imageUrlString; @end // UIImageView+CustomCache.m #import "UIImageView+CustomCache.h" @implementation UIImageView(CustomCache) -(void)startAsyncDownload:(UIImage*)placeHolderImage imageUrlString:(NSString*)imageUrlString{ self.image = placeHolderImage; [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL: [NSURL URLWithString:imageUrlString]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionHandler){ @autoreleasepool { if (connectionHandler != nil) { NSLog(@"error in downloading description %@",connectionHandler.localizedDescription); } else { ImagesCacheHandler *ref = [ImagesCacheHandler new]; UIImage *imageFromData = [[UIImage alloc] initWithData:data]; if (imageFromData != NULL && imageFromData != nil && data.length > 0) { self.image = imageFromData; //custom store to sqlite [ref archiveImage:imageUrlString imageData:data moc:[ref fetchContext]]; } } } }]; } @end 

And in my table view I use (I import of course UIImageView + CustomCache.h)

 UIImageView *imageViewToLazyLoad = (UIImageView*)[cell viewWithTag:1]; [imageViewToLazyLoad startAsyncDownload:[UIImage imageNamed@ "palce_Holder_Image_name"] imageUrlString:imageUrl]; 
+1
source

I personally prefer to use the NSURLConnection sendSynchronousRequest and put a GCD wrapper around it. Keeps everything neat and tidy.

0
source

Source: https://habr.com/ru/post/1402158/


All Articles