📜 ⬆️ ⬇️

Asynchronous loading in iOS

Probably there are enough materials on this topic, including Apple, but I will describe my experience and give my code.

The task is as follows: for some View, which has a certain number of subviews in which you can load images (UIImageView for example), you need to load a number of images asynchronously without locking the main UI.


Our class will be called ImageLoader and will have the ImageLoaderDelegate protocol to be able to inform the delegate when the picture has already “arrived”.
ImageLoader.h
')
#import @protocol ImageLoaderDelegate; //   ,      //    delegate @interface ImageLoader : NSObject { id delegate; //     int index; //         NSMutableData *activeDownloadData; //    } @property (nonatomic, assign) id delegate; @property (nonatomic) int index; - (void)loadImage:(NSString *)imageURLString; // ,   . //    URL   @end @protocol ImageLoaderDelegate - (void) appImageDidLoad:(UIImage *)image index:(int)index; //  ,     @end 

ImageLoader.m
 #import "ImageLoader.h" @implementation ImageLoader @synthesize delegate, index; - (void)loadImage:(NSString *)imageURLString { NSURL *imgURL = [NSURL URLWithString:imageURLString]; NSMutableURLRequest *request = [NSURLRequest requestWithURL:imgURL]; NSURLConnection *newConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; if (newConnection) { activeDownloadData = [[NSMutableData data] retain]; //   -  retain } } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { [activeDownloadData setLength:0]; //    ,    0 } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [activeDownloadData appendData:data]; //    } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ [connection release]; [activeDownloadData release]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { UIImage *image = [UIImage imageWithData:activeDownloadData]; //     if (delegate != nil) { [delegate appImageDidLoad:image index:index]; //    } else { activeDownloadData = nil; NSLog(@"Can't find delegate for ImageLoader"); } [activeDownloadData release]; [connection release]; } - (void)dealloc { [super dealloc]; } @end 

It remains only to insert the image in the desired view.
I give one of the options below. It uses the loader index property to get to the desired view whose tag property has the same index.
By itself, in the header file, you need to make our class a delegate for ImageLoader by adding an interface to the line
 ... - (void)viewDidLoad { [super viewDidLoad]; viewIndex = 0; NSArray *imageUrls = [NSArray arrayWithObjects: //     @"http://cdn5.iconfinder.com/data/icons/toys/128/teddy_bear_toy_1.png", @"http://cdn5.iconfinder.com/data/icons/toys/128/teddy_bear_toy_4.png", @"http://cdn5.iconfinder.com/data/icons/toys/128/teddy_bear_toy_5.png", nil]; for (NSString *imgURL in imageUrls) { ImageLoader *loader = [[ImageLoader alloc] init]; //    UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(10+(100*viewIndex), 50, 100, 100)]; [imgView setTag:viewIndex]; //    ImgView      [[self view] addSubview:imgView]; [imgView release]; [loader setIndex:viewIndex]; //      [loader setDelegate:self]; //      [loader loadImage:imgURL]; //    [loader release]; viewIndex++; } } - (void)appImageDidLoad:(UIImage* )image index:(int)index { //   ImageLoader for (UIView *tmp in [self view].subviews) { //   subview   view  UIImageView c tag = index if ([tmp isKindOfClass:[UIImageView class]] && tmp.tag == index) { [(UIImageView *)tmp setImage:image]; //    } } } ... 

I hope the material will be useful to someone.

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


All Articles