AFNetworking, as read in this article, is version 3.2.0.

This class is a way to add asynchronously loading network images to UIButton

1. Interface file

  • Image download access method
/** Set the image loader used to download the image */ + (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader; */ + (AFImageDownloader *)sharedImageDownloader;Copy the code
  • Method of setting a picture for a button
/** Set the state of the button and the image of the link */ - (void)setImageForState:(UIControlState)state withURL:(NSURL *)url; /** Set the specified state for the button, the specified image link, and the specified placeholder image */ - (void)setImageForState:(UIControlState)state withURL:(NSURL *)url placeholderImage:(nullable UIImage *)placeholderImage; /** Specify the state of the button, specify the image link, specify the placeholder, and specify the picture of the success and failure callback block */ - (void)setImageForState:(UIControlState)state
          withURLRequest:(NSURLRequest *)urlRequest
        placeholderImage:(nullable UIImage *)placeholderImage
                 success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
                 failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
Copy the code
  • Method of setting a background image for a button
/** Set the state of the button and the background image of the image link */ - (void)setBackgroundImageForState:(UIControlState)state withURL:(NSURL *)url; /** Set the specified state for the button, specify the image link, and specify the placeholder background image */ - (void)setBackgroundImageForState:(UIControlState)state withURL:(NSURL *)url placeholderImage:(nullable UIImage *)placeholderImage; /** Set the specified state for the button, specify the image link, specify the placeholder, and specify the background image of the success and failure callback block */ - (void)setBackgroundImageForState:(UIControlState)state
                    withURLRequest:(NSURLRequest *)urlRequest
                  placeholderImage:(nullable UIImage *)placeholderImage
                           success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
                           failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
Copy the code
  • Cancel the image loading method
/ * * cancel button in the specified state of all the images are downloaded * / - (void) cancelImageDownloadTaskForState (UIControlState) state; / * * cancel button in the specified state of all the background images are downloaded * / - (void) cancelBackgroundImageDownloadTaskForState (UIControlState) state;Copy the code

2. Implementation file

2.1.UIButton+_AFNetworking private classification

2.1.1. Image correlation

  • Static characters
/ / ordinary static char AFImageDownloadReceiptNormal; / / highlight the static char AFImageDownloadReceiptHighlighted; / / the selected static char AFImageDownloadReceiptSelected; / / disable static char AFImageDownloadReceiptDisabled;Copy the code
  • A static method
/ * * this method through the incoming control state to return to the corresponding static characters * / static const char * af_imageDownloadReceiptKeyForState (UIControlState state) {switch (state) {case UIControlStateHighlighted:
            return &AFImageDownloadReceiptHighlighted;
        case UIControlStateSelected:
            return &AFImageDownloadReceiptSelected;
        case UIControlStateDisabled:
            return &AFImageDownloadReceiptDisabled;
        case UIControlStateNormal:
        default:
            return&AFImageDownloadReceiptNormal; }}Copy the code
  • Property
/ * * by the Runtime connection object classification to add attributes to the getter * / - (AFImageDownloadReceipt *) af_imageDownloadReceiptForState: (UIControlState) state {return(AFImageDownloadReceipt *)objc_getAssociatedObject(self, af_imageDownloadReceiptKeyForState(state)); } /** add setter */ - (void)af_setImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceiptforState:(UIControlState)state
{
    objc_setAssociatedObject(self, af_imageDownloadReceiptKeyForState(state), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
Copy the code

2.1.2. BackgroundImage related

  • Static characters
/ / ordinary static char AFBackgroundImageDownloadReceiptNormal; / / highlight the static char AFBackgroundImageDownloadReceiptHighlighted; / / the selected static char AFBackgroundImageDownloadReceiptSelected; / / disable static char AFBackgroundImageDownloadReceiptDisabled;Copy the code
  • A static method
/ * * this method through the incoming control state to return to the corresponding static characters * / static const char * af_backgroundImageDownloadReceiptKeyForState (UIControlState state) { switch (state) {case UIControlStateHighlighted:
            return &AFBackgroundImageDownloadReceiptHighlighted;
        case UIControlStateSelected:
            return &AFBackgroundImageDownloadReceiptSelected;
        case UIControlStateDisabled:
            return &AFBackgroundImageDownloadReceiptDisabled;
        case UIControlStateNormal:
        default:
            return&AFBackgroundImageDownloadReceiptNormal; }}Copy the code
  • Property
/** Add getter */ - (AFImageDownloadReceipt) for a class property via the Runtime's associated object *)af_backgroundImageDownloadReceiptForState:(UIControlState)state {return(AFImageDownloadReceipt *)objc_getAssociatedObject(self, af_backgroundImageDownloadReceiptKeyForState(state)); } / * * by the Runtime connection object classification to add attributes to setter * / - (void) af_setBackgroundImageDownloadReceipt: (AFImageDownloadReceipt *)imageDownloadReceiptforState:(UIControlState)state
{
    objc_setAssociatedObject(self, af_backgroundImageDownloadReceiptKeyForState(state), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
Copy the code

2.2. Method implementation

  • Property
/** Add the getter for the sharedImageDownloader attribute to the class via the Runtime associated object */ + (AFImageDownloader *)sharedImageDownloader {returnobjc_getAssociatedObject(self, @selector(sharedImageDownloader)) ? : [AFImageDownloader defaultInstance]; } /** Add setters for the sharedImageDownloader property */ + (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader {
    objc_setAssociatedObject(self, @selector(sharedImageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
Copy the code
  • Image related interface method implementation
- (void)setImageForState:(UIControlState)state withURL:(NSURL *)url {// call the following method [selfsetImageForState:state withURL:url placeholderImage:nil];
}

- (void)setImageForState:(UIControlState)state withURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request addValue:@"image/*" forHTTPHeaderField:@"Accept"];

    [self setImageForState:state withURLRequest:request placeholderImage:placeholderImage success:nil failure:nil];
}

- (void)setImageForState:(UIControlState)state withURLRequest:(NSURLRequest *)urlRequest placeholderImage:(nullable UIImage *)placeholderImage success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure {// This network request will not be repeated if it is in progressif ([self isActiveTaskURLEqualToURLRequest:urlRequest forState:state]) {
        return; } / / cancel the state image download task [self cancelImageDownloadTaskForState: state]; AFImageDownloader *downloader = [self class] sharedImageDownloader]; Equestcache > imageCache = downloader.imageCache; / / get to the cache graphics UIImage * cachedImage = [imageCache imageforRequest: urlRequest withAdditionalIdentifier: nil]; // If there is a cacheif(cachedImage) {// The callback block is called if set to success, otherwise the image is set for the buttonif (success) {
            success(urlRequest, nil, cachedImage);
        } else {
            [self setImage:cachedImage forState:state];
        }
        [self af_setImageDownloadReceipt:nil forState:state]; // If there is no cache}else{// Set the placeholder map first if there is oneif (placeholderImage) {
            [self setImage:placeholderImage forState:state]; } // Start downloading __weak __typeof(self)weakSelf = self; NSUUID *downloadID = [NSUUID UUID]; AFImageDownloadReceipt *receipt; receipt = [downloader downloadImageForURLRequest:urlRequest withReceiptID:downloadID success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) {// If it is the current button download callback __strong __typeof(weakSelf)strongSelf = weakSelf;if([[strongSelf af_imageDownloadReceiptForState: state] receiptID isEqual: downloadID]) {/ / if set the success callback block is invoked, or for the button to set the pictureif (success) {
                               success(request, response, responseObject);
                           } else if(responseObject) {
                               [strongSelf setImage:responseObject forState:state]; } / / will save the download package object attributes nil [strongSelf af_setImageDownloadReceipt: nilforState:state]; } } failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {// If the current button download callback __strong __typeof(weakSelf)strongSelf = weakSelf;if([[strongSelf af_imageDownloadReceiptForState: state] receiptID isEqual: downloadID]) {/ / callback block failureif(failure) { failure(request, response, error); } / / will save the download package object attributes nil [strongSelf af_setImageDownloadReceipt: nilforState:state]; }}]; / / encapsulated with classification properties save images to download objects [self af_setImageDownloadReceipt: receiptforState:state]; }} - (void) cancelImageDownloadTaskForState: (UIControlState) state {/ / by state to obtain images are downloaded AFImageDownloadReceipt * receipt = encapsulated object  [self af_imageDownloadReceiptForState:state];if(receipt ! = nil) {/ / according to the access to download the encapsulated object to cancel the corresponding pictures download task [[self. The class sharedImageDownloader] cancelTaskForImageDownloadReceipt: receipt]; / / to save images are downloaded encapsulated objects attributes nil [self af_setImageDownloadReceipt: nilforState:state]; }}Copy the code
  • BackgroundImage implements related interface methods

The implementation of backgroundImage and the implementation of image are the same except that when you set an image one goes to the backgroundImage and one goes to the image.

- (void)setBackgroundImageForState:(UIControlState)state
                           withURL:(NSURL *)url
{
    [self setBackgroundImageForState:state withURL:url placeholderImage:nil];
}

- (void)setBackgroundImageForState:(UIControlState)state withURL:(NSURL *)url placeholderImage:(nullable UIImage *)placeholderImage  { NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request addValue:@"image/*" forHTTPHeaderField:@"Accept"];

    [self setBackgroundImageForState:state withURLRequest:request placeholderImage:placeholderImage success:nil failure:nil];
}

- (void)setBackgroundImageForState:(UIControlState)state
                    withURLRequest:(NSURLRequest *)urlRequest
                  placeholderImage:(nullable UIImage *)placeholderImage
                           success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
                           failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure
{
    if ([self isActiveBackgroundTaskURLEqualToURLRequest:urlRequest forState:state]) {
        return;
    }

    [self cancelBackgroundImageDownloadTaskForState:state];

    AFImageDownloader *downloader = [[self class] sharedImageDownloader];
    id <AFImageRequestCache> imageCache = downloader.imageCache;

    //Use the image from the image cache if it exists
    UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
    if (cachedImage) {
        if (success) {
            success(urlRequest, nil, cachedImage);
        } else {
            [self setBackgroundImage:cachedImage forState:state];
        }
        [self af_setBackgroundImageDownloadReceipt:nil forState:state];
    } else {
        if (placeholderImage) {
            [self setBackgroundImage:placeholderImage forState:state];
        }

        __weak __typeof(self)weakSelf = self;
        NSUUID *downloadID = [NSUUID UUID];
        AFImageDownloadReceipt *receipt;
        receipt = [downloader
                   downloadImageForURLRequest:urlRequest
                   withReceiptID:downloadID
                   success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) {
                       __strong __typeof(weakSelf)strongSelf = weakSelf;
                       if ([[strongSelf af_backgroundImageDownloadReceiptForState:state].receiptID isEqual:downloadID]) {
                           if (success) {
                               success(request, response, responseObject);
                           } else if(responseObject) {
                               [strongSelf setBackgroundImage:responseObject forState:state];
                           }
                           [strongSelf af_setBackgroundImageDownloadReceipt:nil forState:state];
                       }

                   }
                   failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
                       __strong __typeof(weakSelf)strongSelf = weakSelf;
                       if ([[strongSelf af_backgroundImageDownloadReceiptForState:state].receiptID isEqual:downloadID]) {
                           if (failure) {
                               failure(request, response, error);
                           }
                           [strongSelf  af_setBackgroundImageDownloadReceipt:nil forState:state]; }}]; [self af_setBackgroundImageDownloadReceipt:receiptforState:state];
    }
}

- (void)cancelBackgroundImageDownloadTaskForState:(UIControlState)state {
    AFImageDownloadReceipt *receipt = [self af_backgroundImageDownloadReceiptForState:state];
    if(receipt ! = nil) { [[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:receipt]; [self af_setBackgroundImageDownloadReceipt:nilforState:state]; }}Copy the code
  • Private methods
/ * * determine whether image download requests have ongoing * / - (BOOL) isActiveTaskURLEqualToURLRequest urlRequest (NSURLRequest *)forState:(UIControlState) State {// obtain the image stored in the property according to the State to download the wrapper object AFImageDownloadReceipt *receipt = [self af_imageDownloadReceiptForState:state]; // Compare the two links based on whether they are the samereturn[receipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString]; } / * * determine whether the background image download requests have ongoing * / - (BOOL) isActiveBackgroundTaskURLEqualToURLRequest urlRequest (NSURLRequest *)forState:(UIControlState) State {// implement the same method as above af_backgroundImageDownloadReceiptForState:state];return [receipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString];
}
Copy the code

3. Summary

When we use this category to set the image for the button

  • First of all, according to the control state and picture link to determine whether it is repeated download, if it is repeated download will not continue to proceed.
  • It then cancels ongoing downloads (if any) in the set control state, meaning that only the latest image Settings are valid.
  • And then get the picture downloader cache object images, image from the cache object lookup cache, if there is one cache will be directly added to the button, but if the user set the success callback block, won’t add images to the button, but will call blokc, transfer the results to the user, let the user to deal with.
  • If there is no cache, it determines if there is a placeholder, and if there is, it sets the placeholder for the button.
  • Next, the UUID is used as an identifier to start the image download task, and the task encapsulation object is saved in properties that are named according to the state of the control to be set for the image.
  • After a download task is executed, whether it succeeds or fails, the system obtains the corresponding encapsulation object of the download task based on the set control status. The system compares the identifier and UUID of the encapsulation object of the download task to determine whether it is a callback of the same task. The execution continues only when it is a callback of the same task
  • In the case of successful download, if the user sets the success callback block, block will be called, and the result will be passed to the user for the user to deal with, if not set, the downloaded picture will be directly added to the specified state of the button, and the property of the save download task encapsulation object corresponding to the specified state will be nil.
  • When the download fails, if the user sets the failure callback block, the block is called, passing the result to the user for the user to deal with, and if not, setting nil the property of the save download task encapsulation object corresponding to the specified state.

AFNetworking

AFNetworking (A) — Start using it

Source: reading AFNetworking (2) — AFURLRequestSerialization

Source: reading AFNetworking (3) — AFURLResponseSerialization

AFNetworking (4) — AFSecurityPolicy

Source: reading AFNetworking (5) — AFNetworkReachabilityManager

AFNetworking (6) — Afurlssession Manager

AFNetworking (7) — Afhttpssession Manager

AFNetworking (8) – AFAutoPurgingImageCache

AFNetworking (9) — AFImageDownloader

The source code to read: AFNetworking (10) — AFNetworkActivityIndicatorManager

AFNetworking — UIActivityIndicatorView+AFNetworking

AFNetworking (12) — UIButton+AFNetworking

AFNetworking (13) — UIImageView+AFNetworking

UIProgressView+AFNetworking

AFNetworking — UIRefreshControl+AFNetworking

UIWebView+AFNetworking