Optimization method of loading a large number of network pictures in IOS development

  • 2021-12-12 10:04:36
  • OfStack

How to optimize loading a large number of network pictures in IOS development

1. Overview

Reading a network picture through URL under IOS does not directly put the picture path in the position of the picture path like other programming languages, but requires us to load the network picture through a similar stream before putting the picture into the picture path for display. For example:


-(UIImage *) getImageFromURL:(NSString *)fileURL {
 //NSLog(@" Execute the picture download function ");  
 UIImage * result;  
 NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:fileURL]];
 result = [UIImage imageWithData:data];  
 return result;
}

Loading network pictures can be said to be necessary in network applications. If you simply download pictures without doing multi-threading, caching and other technologies to optimize, the effect and user experience when loading pictures will be very poor.

The optimization ideas are as follows:

(1) Local caching

(2) Asynchronous loading

(3) Use placeholder pictures before loading

2. Optimization method

Method 1: Open an asynchronous thread with NSOperation to download pictures, and replace the placeholder pictures when the download is completed


#import "XNViewController.h"
#import "XNApp.h"

@interface XNViewController ()
@property (nonatomic, strong) NSArray *appList;
@property (nonatomic, strong) NSOperationQueue *queue;
@end

@implementation XNViewController
#pragma mark -  Lazy loading 

- (NSOperationQueue *)queue {
 if (!_queue) _queue = [[NSOperationQueue alloc] init];
 return _queue;
}

// It can be extracted and written into the model 
- (NSArray *)appList {
 if (!_appList) {
 //1. Loading plist To an array 
 NSURL *url = [[NSBundle mainBundle] URLForResource:@"apps.plist" withExtension:nil];
 NSArray *array = [NSArray arrayWithContentsOfURL:url];
 //2. Traversing an array 
 NSMutableArray *arrayM = [NSMutableArray array];
 [array enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
   [arrayM addObject:[XNApp appWithDict:obj]]; // The dictionary is stored in the array ,  Convert to app Object and then add it to the array 
 }];
 _appList = [arrayM copy];
 }
 return _appList;
}

- (void)viewDidLoad {
 [super viewDidLoad];

 self.tableView.rowHeight = 88;

//  NSLog(@"appList-%@",_appList);
}

#pragma mark -  Data source method 
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 return self.appList.count;
}

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

 // Fill each with a model cell
 XNApp *app = self.appList[indexPath.row];
 cell.textLabel.text = app.name; // Set text 

 // Setting Image :  The image in the model is nil Use the default image when , And download the image .  Otherwise, use the memory in the model to cache the image .
 if (!app.image) {
 cell.imageView.image = [UIImage imageNamed:@"user_default"];

 [self downloadImg:indexPath];
 }
 else {
 // Use the memory cache in the model directly 
 cell.imageView.image = app.image;
 }
// NSLog(@"cell--%p", cell);

 return cell;
}

/** Always remember ,  Modify the display through the model .  Instead of trying to modify the display directly */
- (void)downloadImg:(NSIndexPath *)indexPath {
 XNApp *app = self.appList[indexPath.row]; // Get the model corresponding to the change 

 [self.queue addOperationWithBlock: ^{
   NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]]; // Obtain image data 
   UIImage *image = [UIImage imageWithData:imgData];

   // Update in the main thread UI
   [[NSOperationQueue mainQueue] addOperationWithBlock: ^{
     // By modifying the model ,  To modify the data 
     app.image = image;
     // Refresh the specified table row 
     [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
 }];
 }];
}

@end

The above code only does memory caching, not local caching, because this method is not the focus here, and it is not the preferred method. Every time the above code re-enters the application, it will be re-downloaded from the Internet. If you want to continue to optimize the above code, you need to implement local caching yourself.

Method 2: Use the third-party framework SDWebImage

Features:

Dependent libraries are few and comprehensive.

Automatically implement disk caching: The cached picture name is named after the encrypted MD5. (Because the encrypted stack of strings is only 1)

Set the placeholder picture directly when loading the network picture: [imageView sd_setImageWithURL: imageurl placeholderImage: [UIImage imageNamed: @ "xxxxx"]].

On a method to achieve multithreading\ with buffering effect. (Available with parameters of the method, the specific can see the header file)

After modifying the above method with SDWebImage, the code can be simplified as follows:


#pragma mark -  Data source method 
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 return self.appList.count;
}

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

 // Fill each with a model cell
 XNApp *app = self.appList[indexPath.row];
 cell.textLabel.text = app.name; // Set text 

// // Setting Image :  The image in the model is nil Use the default image when , And download the image .  Otherwise, use the memory in the model to cache the image .
// if (!cell.imageView.image) {
// cell.imageView.image = [UIImage imageNamed:@"user_default"];
//
// [self downloadImg:indexPath];
// }
// else {
// // Use the memory cache in the model directly 
// cell.imageView.image = app.image;
// }


 // Use SDWebImage To complete the above functions .  Aim at ImageView.
 //1 Sentences ,  Automatic asynchronous download .  Picture local cache .  Network download .  Automatically set placeholders .
 [cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"user_default"]];


 return cell;
}

/** Always remember ,  Modify the display through the model .  Instead of trying to modify the display directly */
//- (void)downloadImg:(NSIndexPath *)indexPath {
// XNApp *app = self.appList[indexPath.row]; // Get the model corresponding to the change 
//
// [self.queue addOperationWithBlock: ^{
//   NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]]; // Obtain image data 
//   UIImage *image = [UIImage imageWithData:imgData];
//
//   // Update in the main thread UI
//   [[NSOperationQueue mainQueue] addOperationWithBlock: ^{
//     // By modifying the model ,  To modify the data 
//     app.image = image;
//     // Refresh the specified table row 
//     [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
// }];
// }];
//}

@end

[Remarks] One of the parameters in SDWebImage:


*SDWebImageRetryFailed = 1<< 0,   Default option, retry after failure 

*SDWebImageLowPriority = 1<< 1,   Use low priority 

*SDWebImageCacheMemoryOnly = 1<< 2,   Use only memory cache 

*SDWebImageProgressiveDownload = 1<< 3,   Show the current progress 

*SDWebImageRefreshCached = 1<< 4,   Refresh cache 

*SDWebImageContinueInBackground =1 << 5,   Continue downloading images in the background 

*SDWebImageHandleCookies = 1<< 6,   Deal with Cookie

*SDWebImageAllowInvalidSSLCertificates= 1 << 7,   Invalid is allowed SSL Validation 

*SDWebImageHighPriority = 1<< 8,    High priority 

*SDWebImageDelayPlaceholder = 1<< 9    Delayed display of placeholder pictures 



Thank you for reading, hope to help everyone, thank you for your support to this site!


Related articles: