Detailed introduction to iOS SDWebImage

Posted by love_php on Wed, 19 Jan 2022 20:27:02 +0100

In the picture loading framework of iOS, SDWebImage The frequency of use is very high. It supports downloading and caching pictures from the network, and setting pictures to the corresponding UIImageView control or UIButton control. Using SDWebImage to manage image loading related operations in the project can greatly improve the development efficiency and let us focus more on the implementation of business logic. The version explained in this article is version 4.4.2.

1, Introduction to SDWebImage

SDWebImage is a UIImageView extension that supports asynchronous download and caching. The project mainly provides the following functions:

1. A category of UIImageView is provided to load network pictures and manage the cache of network pictures
2. Download Network pictures asynchronously
3. Adopt asynchronous mode, use memory + disk to cache network pictures, and have automatic cache expiration processing mechanism.
4. Support GIF animation
5. Support WebP format
6. Network pictures of the same URL will not be downloaded repeatedly
7. Invalid. False URL s will not be retried indefinitely
8. All time-consuming operations are in the sub thread to ensure that the main thread is not blocked
9. Use GCD and ARC
10. Support Arm64
11. Support background image decompression processing
12. The image formats supported by the project include PNG,JPEG,GIF,Webp, etc

2, SDWebImage organizational structure

Key class explanation

SDWebImageDownloader: responsible for maintaining the image download queue;
SDWebImageDownloaderOperation: responsible for real image download requests;
SDImageCache: responsible for image caching;
SDWebImageManager: it is a general management class. It maintains an SDWebImageDownloader instance and an SDImageCache instance. It is a bridge between download and cache;
SDWebImageDecoder: responsible for image decompression;
SDWebImagePrefetcher: responsible for image prefetching;
UIImageView+WebCache: and other extensions deal directly with users.

The three most important classes are SDWebImageDownloader, SDImageCache and SDWebImageManager. Next, we will study in detail what these classes do and how they do it.

In order to facilitate you to have a macro grasp, here is the framework of the project:

  • UIImageView+WebCache and UIButton+WebCache directly provide interfaces for the surface UIKit framework
  • SDWebImageManger is responsible for handling and coordinating SDWebImageDownloader and SDWebImageCache, and interacting with UIKit layer.
  • SDWebImageDownloaderOperation actually executes the download request; The bottom two classes support high-level abstraction.

3, Detailed explanation of each category

We study each class according to the top-down process in the figure above

3.1 UIImageView+WebCache

Here, only UIImageView+WebCache is used as an example. Other extensions are similar.

Usage scenario: the url address of the picture is known, download the picture and set it to UIImageView.

UIImageView+WebCache provides a series of interfaces:

- (void)sd_setImageWithURL:(nullable NSURL *)url;

- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder;

- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                   options:(SDWebImageOptions)options;

- (void)sd_setImageWithURL:(nullable NSURL *)url
                 completed:(nullable SDExternalCompletionBlock)completedBlock;

- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                 completed:(nullable SDExternalCompletionBlock)completedBlock;

- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock;

- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                   options:(SDWebImageOptions)options
                  progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                 completed:(nullable SDExternalCompletionBlock)completedBlock;

- (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url
                                 placeholderImage:(nullable UIImage *)placeholder
                                          options:(SDWebImageOptions)options
                                         progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                        completed:(nullable SDExternalCompletionBlock)completedBlock;

These interfaces will eventually be called

- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                   options:(SDWebImageOptions)options
                  progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                 completed:(nullable SDExternalCompletionBlock)completedBlock;

The new version also adds a category to UIView, that is, UIView+WebCache. Finally, the above methods will go to the following methods for specific operations, such as downloading pictures.

- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
                  placeholderImage:(nullable UIImage *)placeholder
                           options:(SDWebImageOptions)options
                      operationKey:(nullable NSString *)operationKey
                     setImageBlock:(nullable SDSetImageBlock)setImageBlock
                          progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                         completed:(nullable SDExternalCompletionBlock)completedBlock
                           context:(nullable NSDictionary<NSString *, id> *)context;

Next, the method is analyzed

  • Step 1: cancel the asynchronous download currently in progress. Ensure that there is only one operation in each UIImageView object. Currently, only one image network request is allowed. This operation is responsible for obtaining the image from the cache or downloading the image again. The specific execution code is:
NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]);
// Cancel previously downloaded tasks
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
... // Download picture operation
// Assign the generated load operation to the custom property of UIView
[self sd_setImageLoadOperation:operation forKey:validOperationKey];

The above methods are defined in UIView+WebCacheOperation class

- (void)sd_setImageLoadOperation:(nullable id<SDWebImageOperation>)operation forKey:(nullable NSString *)key {
    if (key) {
        // If you have previously downloaded the picture, cancel the previous picture download operation
        [self sd_cancelImageLoadOperationWithKey:key];
        if (operation) {
            SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
            @synchronized (self) {
                [operationDictionary setObject:operation forKey:key];
            }
        }
    }
}

- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key {
    if (key) {
        // Cancel in progress downloader from queue
        SDOperationsDictionary *operationDictionary = [self sd_operationDictionary]; // Gets the custom property added to the UIView
        id<SDWebImageOperation> operation;

        @synchronized (self) {
            operation = [operationDictionary objectForKey:key];
        }
        if (operation) {
            // The protocol of SDWebImageOperation is implemented
            if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) {
                [operation cancel];
            }
            @synchronized (self) {
                [operationDictionary removeObjectForKey:key];
            }
        }
    }
}

In fact, all operations are maintained by an operationDictionary. All operations are cancel led before a new operation is executed.

  • Step 2: occupy bitmap strategy
    As a substitute image before the image download is completed. dispatch_main_async_safe is a macro that ensures safe execution in the main thread.
if (!(options & SDWebImageDelayPlaceholder)) {
    dispatch_main_async_safe(^{
        // Set duty bitmap
        [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
    });
}
  • Step 3: determine whether the url is legal
    If the url is legal, download the image. Otherwise, the direct block callback fails
if (url) {
    // Download picture operation
} else {
    dispatch_main_async_safe(^{
#if SD_UIKIT
        [self sd_removeActivityIndicator];
#endif
        if (completedBlock) {
            NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
            completedBlock(nil, error, SDImageCacheTypeNone, url);
        }
    });
}
  • Step 4 download pictures
    The operation of downloading images is completed by SDWebImageManager, which is a single example
- (id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
                                     options:(SDWebImageOptions)options
                                    progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                   completed:(nullable SDInternalCompletionBlock)completedBlock;

Refresh the UIImageView image after downloading.

// Judge whether to set the picture according to the enumeration type
shouldCallCompletedBlock = finished || (options & SDWebImageAvoidAutoSetImage);
BOOL shouldNotSetImage = ((image && (options & SDWebImageAvoidAutoSetImage)) ||
                          (!image && !(options & SDWebImageDelayPlaceholder)));
SDWebImageNoParamsBlock callCompletedBlockClojure = ^{
    if (!sself) { return; }
    if (!shouldNotSetImage) {
        [sself sd_setNeedsLayout];  // Set picture
    }
    if (completedBlock && shouldCallCompletedBlock) {
        completedBlock(image, error, cacheType, url);
    }
};

if (shouldNotSetImage) {    // If the picture is not set automatically, call block to pass in the image object
    dispatch_main_async_safe(callCompletedBlockClojure);
    return;
}

// Set picture operation
dispatch_main_async_safe(^{
#if SD_UIKIT || SD_MAC
    [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL];
#else
    [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock];
#endif
    callCompletedBlockClojure();
});

Finally, the returned id operation is added to the operationDictionary to facilitate subsequent cancel lations.

// Assign the generated load operation to the custom property of UIView
[self sd_setImageLoadOperation:operation forKey:validOperationKey];

3.2 SDWebImageManager

In SDWebImageManager H describes the SDWebImageManager class as follows:

 /**
 * The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
 * It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
 * You can use this class directly to benefit from web image downloading with caching in another context than
 * a UIView.
*/

That is, the classes hidden behind UIImageView+WebCache are used to handle asynchronous downloading and image caching. Of course, you can also directly download images using the SDWebImageManager method.

- (nullable id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
                                              options:(SDWebImageOptions)options
                                             progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                            completed:(nullable SDInternalCompletionBlock)completedBlock;

SDWebImageManager.h first defines some enumerated types of SDWebImageOptions.

Then, four block s are declared:

// The callback after the operation is completed is called by the upper level extension.
typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);

// Called by SDWebImageManager.
// If the SDWebImageProgressiveDownload flag is used, this block may be called repeatedly until the picture is completely downloaded,
// finished=true, and finally call this block once.
typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);

// SDWebImageManager is called every time the URL is converted into a cache key, and some dynamic parts of the image URL can be deleted.
typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);

typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL);

SDWebImageManagerDelegate protocol is defined:

@protocol SDWebImageManagerDelegate 

@optional
// Controls whether an image should be downloaded when it is not found in the cache.
- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;

// After downloading, convert the picture before caching. Operate in the global queue without blocking the main thread
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;

@end

SDWebImageManager is used as a single instance, maintaining an SDImageCache instance and an SDWebImageDownloader instance respectively. Object methods are:

// Initialize the SDWebImageManager singleton. The cache singleton and the downloader singleton have been initialized in the init method.
- (instancetype)initWithCache:(SDImageCache *)cache downloader:(SDWebImageDownloader *)downloader;
// Download pictures
- (id )downloadImageWithURL:(NSURL *)url
                    options:(SDWebImageOptions)options
                   progress:(SDWebImageDownloaderProgressBlock)progressBlock
                  completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
// Cache pictures for a given URL
- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
// Cancel all current operations
- (void)cancelAll;
// Monitor whether there are currently operations in progress
- (BOOL)isRunning;
// Monitor whether the picture is in the cache. First find it in the memory cache, and then find it in the disk cache
- (BOOL)cachedImageExistsForURL:(NSURL *)url;
// Monitor whether the pictures are cached in the disk
- (BOOL)diskImageExistsForURL:(NSURL *)url;
// Monitor pictures in cache and call completionBlock after monitoring.
- (void)cachedImageExistsForURL:(NSURL *)url
                     completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
// Monitor whether the picture is cached in disk, and call completionBlock after monitoring.
- (void)diskImageExistsForURL:(NSURL *)url
                   completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
//Returns the cache key of the given URL
- (NSString *)cacheKeyForURL:(NSURL *)url;

Our main research

- (nullable id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
                                              options:(SDWebImageOptions)options
                                             progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                            completed:(nullable SDInternalCompletionBlock)completedBlock;

1. First, monitor the legitimacy of the url:

if ([url isKindOfClass:NSString.class]) {
    url = [NSURL URLWithString:(NSString *)url];
}
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
if (![url isKindOfClass:NSURL.class]) {
    url = nil;
}

The first judgment condition is to prevent errors caused by many users directly passing NSString as NSURL, and the second judgment condition is to prevent crash.

2. The collection failedURLs saves urls that failed before. If the url is empty or the url failed before and does not adopt the retry strategy, directly call completedBlock to return an error.

BOOL isFailedUrl = NO;
if (url) {  // Determine whether the url is a failed url
    LOCK(self.failedURLsLock);
    isFailedUrl = [self.failedURLs containsObject:url];
    UNLOCK(self.failedURLsLock);
}
// If the url is empty or the url download fails and is set, do not try again
if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
    [self callCompletionBlockForOperation:operation completion:completedBlock error:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil] url:url];
    return operation;
}

3. Save

LOCK(self.runningOperationsLock);
[self.runningOperations addObject:operation];
UNLOCK(self.runningOperationsLock);

runningOperations is a variable array that holds all operations. It is mainly used to monitor whether there are operations executing, that is, to judge the running status.

4. Find cache
SDWebImageManager will first find out whether the same photos have been downloaded in memory and disk cache, that is, call the following method of imageCache

- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock;

If the operation is cancelled, return directly

__strong __typeof(weakOperation) strongOperation = weakOperation;
if (!strongOperation || strongOperation.isCancelled) {  // If the operation is cancelled, the download task will be directly removed from the download queue
    [self safelyRemoveOperationFromRunning:strongOperation];
    return;
}

If the image is not found in the cache, or no matter whether the image is found or not, as long as the operation is marked with SDWebImageRefreshCached, if the shouldDownloadImageForURL method of SDWebImageManagerDelegate returns true, that is, the download method of imageDownloader is used when downloading is allowed

- (id )downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock

If there is an error in downloading, directly call completedBlock to return an error, and add the url to failedURLs as appropriate;

dispatch_main_sync_safe(^{
    if (strongOperation && !strongOperation.isCancelled) {
        completedBlock(nil, error, SDImageCacheTypeNone, finished, url);
    }
});

if (error.code != NSURLErrorNotConnectedToInternet
 && error.code != NSURLErrorCancelled
 && error.code != NSURLErrorTimedOut
 && error.code != NSURLErrorInternationalRoamingOff
 && error.code != NSURLErrorDataNotAllowed
 && error.code != NSURLErrorCannotFindHost
 && error.code != NSURLErrorCannotConnectToHost) {
      @synchronized (self.failedURLs) {
          [self.failedURLs addObject:url];
      }
}

If the download succeeds, if the support fails, try again, and delete the url from the failURLs:

if ((options & SDWebImageRetryFailed)) {
    @synchronized (self.failedURLs) {
         [self.failedURLs removeObject:url];
    }
}

If delegate implements the imageManager:transformDownloadedImage:withURL: method, the image needs to be transformed before it is cached (called in the global queue, not blocking the main thread). The conversion is successful, the download is completed, the picture is stored in the cache, and the completedBlock callback is called. The first parameter is the converted image.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];

    if (transformedImage && finished) {
        BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
        //Cache pictures
        [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:(imageWasTransformed ? nil : data) forKey:key toDisk:cacheOnDisk];
    }
    dispatch_main_sync_safe(^{
        if (strongOperation && !strongOperation.isCancelled) {
            completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
        }
    });
});

Otherwise, it is directly stored in the cache and the completedBlock callback is called. The first parameter is the downloaded original image.

if (downloadedImage && finished) {
    [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
}

dispatch_main_sync_safe(^{
    if (strongOperation && !strongOperation.isCancelled) {
        completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
    }
});

The following methods of imageCache are called to store the cache

- (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk

If no picture is found in the cache and downloading is not allowed, call completedBlock directly, and the first parameter is nil.

dispatch_main_sync_safe(^{
    __strong __typeof(weakOperation) strongOperation = weakOperation;
    if (strongOperation && !weakOperation.isCancelled) {//Why is weakOperation TODO used here
        completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
    }
});

Finally, delete this operation from running operations.

@synchronized (self.runningOperations) {
    [self.runningOperations removeObject:operation];
 }

3.3 SDWebImageCombinedOperation

@interface SDWebImageCombinedOperation : NSObject 

@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
@property (strong, nonatomic) NSOperation *cacheOperation;

@end

Is an NSObject subclass that follows the SDWebImageOperation protocol.

@protocol SDWebImageOperation 

- (void)cancel;

@end

Encapsulate an NSOperation in it. The purpose of this should be to make the code more concise. Because the download operation needs to query the cached operation and the actual downloaded operation, the cancel method of this class can cancel two operations at the same time and maintain a state cancelled at the same time.

SDWebImage usage

1. Use UIImageView+WebCache category to load the pictures of cell s in UITableView

[imageView sd_setImageWithURL:[NSURL URLWithString:@"http://img1.cache.netease.com/catchpic/5/51/5132C377F99EEEE927697E62C26DDFB1.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

2. Using Blocks, you can know the picture download progress and whether the picture loading is successful during the network picture loading process

[imageView sd_setImageWithURL:[NSURL URLWithString:@"http://img1.cache.netease.com/catchpic/5/51/5132C377F99EEEE927697E62C26DDFB1.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
    // ... completion code here ... 
 }];

3. Use SDWebImageManager, which provides an interface for the implementation of UIImageView+WebCache category.

SDWebImageManager *manager = [SDWebImageManager sharedManager] ;
[manager downloadImageWithURL:imageURL options:0 progress:^(NSInteger   receivedSize, NSInteger expectedSize) { 
     // progression tracking code
 }  completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType,   BOOL finished, NSURL *imageURL) { 
    if (image) { 
        // do something with image
    }
}];

4. SDWebImageDownloader and SDImageCache are also used to load images

5. Source of key

// The key required to generate a cache using the URL of the Image
// There are two cases. The first is to use the cacheKeyFilter to process the URL and generate a key if it is detected that the cacheKeyFilter is not empty
// If it is empty, the string content of the URL is directly returned as the key
- (NSString *)cacheKeyForURL:(NSURL *)url {
    if (self.cacheKeyFilter) {
        return self.cacheKeyFilter(url);
    }
    else {
        return [url absoluteString];
    }
}

SDWebImage process

SDWebImage interface

SDWebImage is a mature and relatively large framework, but it does not need too many interfaces in the process of use, which is a reflection of the degree of code encapsulation. Here are some commonly used interfaces.

1. Set the picture interface for UIImageView. SDWebImage provides multiple interfaces for setting pictures for UIImageView. Finally, all interfaces will call the interface shown in the figure below, which is the practice of most frameworks.

///Therefore, the method of setting the picture will eventually call this method
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {
}

2. Obtain the disk cache size of SDWebImage. In the project, it is sometimes necessary to count the disk cache content size of the application, so this interface is used to obtain the image cache size

[SDImageCache sharedImageCache] getSize];

3. Clear the memory cache, clear the cached picture resources in the memory, and release the memory resources.

[[SDImageCache sharedImageCache] clearMemory];

4. With the interface to clean up the memory cache, there is naturally an interface to clean up the disk cache

[[SDImageCache sharedImageCache] clearDisk];

SDWebImage parsing

<1> Entry setImageWithURL:placeholderImage:options: the placeholderImage will be displayed first, and then the SDWebImageManager will start processing the image according to the URL.

<2> Enter sdwebimagemanager downloadwithurl: delegate: options: userinfo:, and give it to SDImageCache to find out whether the picture has been downloaded from the cache. queryDiskCacheForKey:delegate:userInfo:.

<3> First, check whether there is a picture from the in memory picture cache. If there is already a picture cache in memory, sdimagecachedelete calls back imageCache:didFindImage:forKey:userInfo: to SDWebImageManager.

<4> Sdwebimagemanagerdelegate callback webImageManager:didFinishWithImage: to UIImageView+WebCache and other front-end display pictures.

<5> If there is no in the memory cache, the generated NSInvocationOperation is added to the queue to start looking for whether the picture has been cached from the hard disk.

<6> Try to read the picture file in the hard disk cache directory according to the URLKey. This step is an operation performed in NSOperation, so the main thread is returned for the result callback notifyDelegate:.

<7> If a picture is read from the hard disk in the previous operation, add the picture to the memory cache (if the free memory is too small, the memory cache will be emptied first). Sdimagecachedelete callback imageCache:didFindImage:forKey:userInfo:. Then show the picture.

<8> If the picture cannot be read from the hard disk cache directory, it means that the picture does not exist in all caches. You need to download the picture and call back imageCache:didNotFindImageForKey:userInfo:.

<9> Share or regenerate a downloader SDWebImageDownloader to start downloading images.

<10> The image download is done by the NSURLConnection, and the relevant delegate is implemented to judge the image download, Download completion and download failure.

<11> Connection: didreceivedata: uses ImageIO to load images according to the download progress.

<12> Connectiondidfinishloading: after the data is downloaded, submit it to SDWebImageDecoder for image decoding.

<13> The image decoding process is completed in an NSOperationQueue, which will not slow down the mainline UI. If there is a need for secondary processing of downloaded images, it is best to complete it here, and the efficiency will be much better.

<14> In the main thread, notifyDelegateOnMainThreadWithInfo: declares that decoding is complete, and imageDecoder:didFinishDecodingImage:userInfo: callback to SDWebImageDownloader.

<15> Imagedownloader: didfinishwithimage: call back to SDWebImageManager to inform it that the image download is complete.

<16> Notify all downloadDelegates that the download is complete, and call back to show the pictures where needed.

<17> Save the picture to SDImageCache, memory cache and hard disk cache at the same time. Writing files to the hard disk is also completed with a separate NSInvocationOperation to avoid slowing down the main thread.

<18> Sdimagecache will register some message notifications during initialization, clean up the memory picture cache when the memory is warned or retreated to the background, and clean up the expired pictures when the application is finished.

<19> Sdwebimage also provides UIButton+WebCache and MKAnnotationView+WebCache for easy use.

<20> Sdwebimageprefetcher can download pictures in advance to facilitate subsequent use.

As can be seen from the above process, when you call the setImageWithURL: method, it will automatically do so many things for you. When you need to do something at a specific time, you can override these methods. For example, to respond to an event during downloading an image, override this method:

// The overwrite method refers to the method of "where to hit". This method is the response when downloading imagePath2
SDWebImageManager *manager = [SDWebImageManager sharedManager];

[manager downloadImageWithURL:imagePath2 options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {
    NSLog(@"Show current progress");
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
    NSLog(@"Download complete");
}];

Topics: iOS objective-c