text: // UIButton+AFNetworking.m
  // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
  //
  // Permission is hereby granted, free of charge, to any person obtaining a copy
  // of this software and associated documentation files (the "Software"), to deal
  // in the Software without restriction, including without limitation the rights
  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the Software is
  // furnished to do so, subject to the following conditions:
  //
  // The above copyright notice and this permission notice shall be included in
  // all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  // THE SOFTWARE.
  
  #import "UIButton+AFNetworking.h"
  
  #import <objc/runtime.h>
  
  #if TARGET_OS_IOS || TARGET_OS_TV
  
  #import "UIImageView+AFNetworking.h"
  #import "AFImageDownloader.h"
  
  @interface UIButton (_AFNetworking)
  @end
  
  @implementation UIButton (_AFNetworking)
  
  #pragma mark -
  
  static char AFImageDownloadReceiptNormal;
  static char AFImageDownloadReceiptHighlighted;
  static char AFImageDownloadReceiptSelected;
  static char AFImageDownloadReceiptDisabled;
  
  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;
      }
  }
  
  - (AFImageDownloadReceipt *)af_imageDownloadReceiptForState:(UIControlState)state {
      return (AFImageDownloadReceipt *)objc_getAssociatedObject(self, af_imageDownloadReceiptKeyForState(state));
  }
  
  - (void)af_setImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt
                             forState:(UIControlState)state
  {
      objc_setAssociatedObject(self, af_imageDownloadReceiptKeyForState(state), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  }
  
  #pragma mark -
  
  static char AFBackgroundImageDownloadReceiptNormal;
  static char AFBackgroundImageDownloadReceiptHighlighted;
  static char AFBackgroundImageDownloadReceiptSelected;
  static char AFBackgroundImageDownloadReceiptDisabled;
  
  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;
      }
  }
  
  - (AFImageDownloadReceipt *)af_backgroundImageDownloadReceiptForState:(UIControlState)state {
      return (AFImageDownloadReceipt *)objc_getAssociatedObject(self, af_backgroundImageDownloadReceiptKeyForState(state));
  }
  
  - (void)af_setBackgroundImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt
                                       forState:(UIControlState)state
  {
      objc_setAssociatedObject(self, af_backgroundImageDownloadReceiptKeyForState(state), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  }
  
  @end
  
  #pragma mark -
  
  @implementation UIButton (AFNetworking)
  
  + (AFImageDownloader *)sharedImageDownloader {
  
      return objc_getAssociatedObject(self, @selector(sharedImageDownloader)) ?: [AFImageDownloader defaultInstance];
  }
  
  + (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader {
      objc_setAssociatedObject(self, @selector(sharedImageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  }
  
  #pragma mark -
  
  - (void)setImageForState:(UIControlState)state
                   withURL:(NSURL *)url
  {
      [self setImageForState: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
  {
      if ([self isActiveTaskURLEqualToURLRequest:urlRequest forState:state]) {
          return;
      }
  
      [self cancelImageDownloadTaskForState: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 setImage:cachedImage forState:state];
          }
          [self af_setImageDownloadReceipt:nil forState:state];
      } else {
          if (placeholderImage) {
              [self setImage: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_imageDownloadReceiptForState:state].receiptID isEqual:downloadID]) {
                             if (success) {
                                 success(request, response, responseObject);
                             } else if(responseObject) {
                                 [strongSelf setImage:responseObject forState:state];
                             }
                             [strongSelf af_setImageDownloadReceipt:nil forState:state];
                         }
  
                     }
                     failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
                         __strong __typeof(weakSelf)strongSelf = weakSelf;
                         if ([[strongSelf af_imageDownloadReceiptForState:state].receiptID isEqual:downloadID]) {
                             if (failure) {
                                 failure(request, response, error);
                             }
                             [strongSelf  af_setImageDownloadReceipt:nil forState:state];
                         }
                     }];
  
          [self af_setImageDownloadReceipt:receipt forState:state];
      }
  }
  
  #pragma mark -
  
  - (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:receipt forState:state];
      }
  }
  
  #pragma mark -
  
  - (void)cancelImageDownloadTaskForState:(UIControlState)state {
      AFImageDownloadReceipt *receipt = [self af_imageDownloadReceiptForState:state];
      if (receipt != nil) {
          [[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:receipt];
          [self af_setImageDownloadReceipt:nil forState:state];
      }
  }
  
  - (void)cancelBackgroundImageDownloadTaskForState:(UIControlState)state {
      AFImageDownloadReceipt *receipt = [self af_backgroundImageDownloadReceiptForState:state];
      if (receipt != nil) {
          [[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:receipt];
          [self af_setBackgroundImageDownloadReceipt:nil forState:state];
      }
  }
  
  - (BOOL)isActiveTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest forState:(UIControlState)state {
      AFImageDownloadReceipt *receipt = [self af_imageDownloadReceiptForState:state];
      return [receipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString];
  }
  
  - (BOOL)isActiveBackgroundTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest forState:(UIControlState)state {
      AFImageDownloadReceipt *receipt = [self af_backgroundImageDownloadReceiptForState:state];
      return [receipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString];
  }
  
  
  @end
  
  #endif
  