SDWebImage源碼閱讀(一)SDWebImageCompat

  SDWebImageCompat 是SDWebImage 的配置文件,裏面利用條件編譯對Apple 的各個平臺進行了兼容。能夠看到SDWebImage 支持當前的MAC/iOS/TV/WATCH 平臺。php

  對各個平臺的兼容性對框架開發意義重大。當前咱們只是針對iOS 平臺進行閱讀理解,可是咱們應該知道,當咱們在別的Apple 的平臺開發時,咱們依然能夠親切並熟練的使用SDWebImage。html

  (1): 導入 #import <TargetConditionals.h>ios

  按英語字面意思能夠翻譯爲「目標依賴」,這個文件裏面所有都是宏定義,主要定義了Apple 各系統平臺和各CPU類型相關的宏。主要用於開發的時候針對不一樣的開發環境作配置使用。SDWebImageCompat 裏面TARGET_OS 開頭的宏定義都來自這裏:segmentfault

 1     #define TARGET_OS_MAC               1
 2     #define TARGET_OS_WIN32             0
 3     #define TARGET_OS_UNIX              0
 4     #define TARGET_OS_OSX               0
 5     #define TARGET_OS_IPHONE            1
 6     #define TARGET_OS_IOS               1
 7     #define TARGET_OS_WATCH             0
 8     #define TARGET_OS_BRIDGE            0
 9     #define TARGET_OS_TV                0
10     #define TARGET_OS_SIMULATOR         1
11     #define TARGET_OS_EMBEDDED          0 
12     #define TARGET_IPHONE_SIMULATOR     TARGET_OS_SIMULATOR /* deprecated */
13     #define TARGET_OS_NANO              TARGET_OS_WATCH /* deprecated */ 

  (2): 條件編譯 __OBJC_GC__api

1 #ifdef __OBJC_GC__
2     #error SDWebImage does not support Objective-C Garbage Collection
3 #endif

  Objective-C 支持內存的垃圾回收機制(Garbage collection 簡稱:GC)。在Mac開發是支持的,可是在iOS 開發中使用MRC/ARC,是不支持GC 的。app

iOS 5 以後開始支持ARC ,幫助開發者更好的管理內存,簡化內存管理的難度並提升開發效率。框架

  SDWebImage 不支持GC,若是宏定義過 __OBJC_GC__,則表示是在支持GC 的開發環境,直接報錯(#error)。iphone

  當啓動GC時,全部的retain、autorelease、release 和dealloc 方法都將被系統忽略。異步

  延伸: async

  __OBJC__ 的使用:在OC 項目工程的pch 文件中咱們常常能見到 :

1 #ifdef __OBJC__
2 // 中間引入OC 的頭文件
3 #endif

  這樣的預編譯,這是由於在一個OC 工程中,可能會包含.m/.mm/.c/.cpp 這4類編譯文件,這4類文件都會引入pch 文件裏的預編譯頭,在編譯.c/.cpp 文件時,由於他們是C 語言的文件,它們的語法是不兼容OC的,因此預編譯頭中是不能包含OC 代碼,可是pch 是兩類源文件共用的,因此在pch 中,OC 的頭文件用__OBJC__ 包含起來,表示__OBJC__ 內引入的頭文件只被使用OC 語言的文件所使用,保證引用關係的清晰。

參考連接:https://segmentfault.com/q/1010000000192619

http://www.jianshu.com/p/f3f4ba69e931

http://www.cnblogs.com/tekkaman/archive/2013/02/25/2931984.html

https://zhidao.baidu.com/question/328947129.html

   (3): #define SD_MAC

1 // Apple's defines from TargetConditionals.h are a bit weird.
2 // Seems like TARGET_OS_MAC is always defined (on all platforms).
3 // To determine if we are running on OSX, we can only relly on TARGET_OS_IPHONE=0 and all the other platforms
4 #if !TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH
5     #define SD_MAC 1
6 #else
7     #define SD_MAC 0
8 #endif

  蘋果的TARGET 宏定義都來自 TargetConditionals.h 是有一點怪。

  TARGET_OS_MAC 好像老是定義在全部的平臺中 MAC Iphone Watch TV,單純的使用TARGET_OS_MAC 判斷當前是否是MAC 平臺是不可行的。

當前 TargetConditionals.h 中 TARGET_OS_MAC 的宏定義是 1:

1     #define TARGET_OS_MAC               1

  爲肯定當前是運行在 OSX 平臺,咱們只能除了TARGET_OS_MAC,其它全部平臺的都是0。(!TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH),而這樣判斷的缺點也很明顯,當Apple 出現新的平臺時,就要對判斷條件進行修改,增長新的平臺爲!。

  (4): #define SD_UIKIT

1 // iOS and tvOS are very similar, UIKit exists on both platforms
2 // Note: watchOS also has UIKit, but it's very limited
3 #if TARGET_OS_IOS || TARGET_OS_TV
4     #define SD_UIKIT 1
5 #else
6     #define SD_UIKIT 0
7 #endif

  iOS 和 tvOS 是很是像的,UIKit 存在於它們兩個平臺上。

  watchOS 也有UIKit,可是它是很是受限的。當開發平臺是iOS 或者TV 的時候宏定義 SD_UIKIT 爲真。

  SDWebImageCompat.h 下面當SD_UIKIT 爲真的時候引入 <UIKit/UIKit.h>。

  (5): #define SD_IOS/#define SD_TV/#define SD_WATCH

 1 #if TARGET_OS_IOS
 2     #define SD_IOS 1
 3 #else
 4     #define SD_IOS 0
 5 #endif
 6 
 7 #if TARGET_OS_TV
 8     #define SD_TV 1
 9 #else
10     #define SD_TV 0
11 #endif
12 
13 #if TARGET_OS_WATCH
14     #define SD_WATCH 1
15 #else
16     #define SD_WATCH 0
17 #endif

  宏定義 SD_IOS/SD_TV/SD_WATCH 用於區分不一樣的開發平臺。

  (6): #if SD_MAC / #else / #endif

 1 #if SD_MAC
 2     #import <AppKit/AppKit.h>
 3     #ifndef UIImage
 4         #define UIImage NSImage
 5     #endif
 6     #ifndef UIImageView
 7         #define UIImageView NSImageView
 8     #endif
 9     #ifndef UIView
10         #define UIView NSView
11     #endif
12 #else
13     #if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
14         #error SDWebImage doesn't support Deployment Target version < 5.0
15     #endif
16 
17     #if SD_UIKIT
18         #import <UIKit/UIKit.h>
19     #endif
20     #if SD_WATCH
21         #import <WatchKit/WatchKit.h>
22     #endif
23 #endif

  若是SD_MAC 爲真,即在macOS 平臺上開發,引入 <AppKit/AppKit.h> 並定義了三個宏 UIImage/UIImageView/UIView。 

 

  系統的宏 __IPHONE_OS_VERSION_MIN_REQUIRED 對應着Xcode deployment target 的系統版本,且__IPHONE_OS_VERSION_MIN_REQUIRED 的值隨着設置的值而改變,始終與你設置的值保持一致。TARGETS -> General -> Deployment Info -> Deployment Target 即:

  

  默認是空白的。

  __IPHONE_OS_VERSION_MIN_REQUIRED 定義在 usr/include -> AvailabilityInternal.h 中:

1 #ifndef __IPHONE_OS_VERSION_MIN_REQUIRED
2     #ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
3         /* compiler sets __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ when -miphoneos-version-min is used */
4         #define __IPHONE_OS_VERSION_MIN_REQUIRED __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
5     #endif
6 #endif

 

   系統的宏 __IPHONE_OS_VERSION_MAX_ALLOWED 對應着Xcode Architecture Base SDK 的版本。TARGETS ->General -> 搜索(Architecture) -> Architectures -> Base SDK 即:

  

  默認是當前Xcode 裏面全部的SDK 的最高版本的以前的版本。( 當前Xcode SDK 最高版本是10.2,因此Base SDK 是 Latest iOS(iOS 10.2) )

  __IPHONE_OS_VERSION_MAX_ALLOWED 定義在 usr/include -> AvailabilityInternal.h 中:

 1 #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
 2     /* make sure a default max version is set */
 3     #ifndef __IPHONE_OS_VERSION_MAX_ALLOWED
 4         #define __IPHONE_OS_VERSION_MAX_ALLOWED     __IPHONE_10_2
 5     #endif
 6     /* make sure a valid min is set */
 7     #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_2_0
 8         #undef __IPHONE_OS_VERSION_MIN_REQUIRED
 9         #define __IPHONE_OS_VERSION_MIN_REQUIRED    __IPHONE_2_0 
10     #endif
11 ...
12 ...

  __IPHONE_10_2 定義在 usr/include -> Availability.h 中:

 1 #define __IPHONE_2_0      20000
 2 #define __IPHONE_2_1      20100
 3 #define __IPHONE_2_2      20200
 4 #define __IPHONE_3_0      30000
 5 #define __IPHONE_3_1      30100
 6 #define __IPHONE_3_2      30200
 7 #define __IPHONE_4_0      40000
 8 #define __IPHONE_4_1      40100
 9 #define __IPHONE_4_2      40200
10 #define __IPHONE_4_3      40300
11 #define __IPHONE_5_0      50000
12 #define __IPHONE_5_1      50100
13 #define __IPHONE_6_0      60000
14 #define __IPHONE_6_1      60100
15 #define __IPHONE_7_0      70000
16 #define __IPHONE_7_1      70100
17 #define __IPHONE_8_0      80000
18 #define __IPHONE_8_1      80100
19 #define __IPHONE_8_2      80200
20 #define __IPHONE_8_3      80300
21 #define __IPHONE_8_4      80400
22 #define __IPHONE_9_0      90000
23 #define __IPHONE_9_1      90100
24 #define __IPHONE_9_2      90200
25 #define __IPHONE_9_3      90300
26 #define __IPHONE_10_0    100000
27 #define __IPHONE_10_1    100100
28 #define __IPHONE_10_2    100200
29 /* __IPHONE_NA is not defined to a value but is uses as a token by macros to indicate that the API is unavailable */

  它包括了全部的iOS 系統的值,最後一個爲當前Xcode 包含的SDK的最高版本。( 因爲Xcode 沒有升級,因此暫時最高到 10.2 )

  三個宏分別對應的頭文件的引用:

1 #import <Availability.h>
2 #import <AvailabilityMacros.h>
3 #import <AvailabilityInternal.h>

  __IPHONE_OS_VERSION_MIN_REQUIRED/ __IPHONE_OS_VERSION_MAX_ALLOWED 會隨着主動設置的值的改變而改變,因此用這兩個宏作API 的兼容,每每存在缺陷。

  對於僅僅是判斷某個方法是否可使用,用 + (BOOL)respondsToSelector:(SEL)aSelector 方法便可。

  若是是判斷當前Device 的iOS 版本,可使用UIDevice 類提供的方法進行判斷。

  示例:

 1 - (BOOL)osVersionAbove:(NSString *)aVersion{
 2     BOOL res;
 3     NSString *currentVersion = [UIDevice currentDevice].systemVersion;
 4     NSComparisonResult cmpRes = [currentVersion compare:aVersion options:NSNumericSearch];
 5     if (cmpRes == NSOrderedSame || cmpRes == NSOrderedDescending) {
 6         res = YES;
 7     }else{
 8         res = NO;
 9     }
10     return res;
11 }

  

 1 #ifdef __IPHONE_7_0
 2     if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
 3         // 代碼段
 4     }
 5 #endif
 6     
 7 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
 8     if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
 9         // 代碼段
10     }
11 #endif

  當使用framework或者.a的時候須要注意:

  由於在編譯framework或者.a的時候是依賴當時編譯的環境決定的,如使用iOS6的sdk能夠將framework或者.a順利編譯經過,可是在真正生成app的時候須要保證編譯app時的sdk和編譯framework或者.a的sdk是一致的,且同時須要加入運行時判斷([[[UIDevice currentDevice] systemVersion] floatValue]那個)

  說明:

  一、若是是使用低版本sdk編譯的(如iOS6),將最終的應用安裝至高版本的設備上(iOS7的系統),此時應該不會出現問題,由於iOS7兼容iOS6,可是沒法使用iOS7特有的新功能,由於代碼被屏蔽了。

  二、若是是使用高版本sdk編譯的(如iOS7),將最終的應用安裝至低版本的設備上(iOS6的系統),此時若是不加入運行時判斷就會出現問題(多是crash)。由於應用自己是用iOS7編譯的,並使用iOS7纔有的新功能,而設備並不支持iOS7。

  簡單來講, 這些編譯期常量, 對運行時的環境判斷徹底無效, 它告訴編譯器用哪一段代碼來進行編譯, 在那段代碼裏, 你仍然能夠寫運行到目標機器裏會崩潰的代碼, 從stackoverflow裏拷兩段示例代碼出來:

 1     // MAX:
 2 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 50000
 3     //you can use iOS 5 APIs here because the SDK supports them
 4     //but the code may still crash if run on an iOS 4 device
 5 #else
 6     //this code can’t use iOS 5 APIs as the SDK version doesn’t support them
 7 #endif
 8     // MIN:
 9 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
10     //minimum deployment target is 5.0, so it’s safe to use iOS 5-only code
11 #else
12     //you can use iOS5 APIs, but the code will need to be backwards
13     //compatible or it will crash when run on an iOS 4 device  (向後兼容(Backward Compatibility),又稱做向下兼容(Downward Compatibility)。在計算機中指在一個程序或者類庫更新到較新的版本後,用舊的版本程序建立的文檔或系統仍能被正常操做或使用,或在舊版本的 類庫的基礎上開發的程序仍能正常編譯運行的狀況。)
14 #endif

  若是碰到這個場景, 須要使用UIAlertViewController(ios8+),我能用上述哪一種寫法呢? 答案是, 都不行.

  max的取值來自於你的sdk的版本, 好比如今個人是Xcode6.1, sdk版本是iOS 8.1, 那麼這個宏的值永遠是80100, 也就是說, 會直接使用UIAlertViewController, 若是這個app跑在了iOS 7上, 就掛了. 因此單純這麼寫只解決了你的ios8的api跑到低版本的xCode的時候不會報編譯錯誤.

  min的取值來自於你項目的deployment target, 即你的app願意支持的最低版本. 從這個角度來講, 片斷2寫法只對作可移植的包的開發團隊有用, 即不知道使用方會將deployment target設成幾. 而沒有這個需求的, 這種寫法就浪費了, 即你既然設定了最低支持ios6, 那麼還寫一段代碼來判斷若是最低支持ios7的狀況下應該怎麼作幹嗎呢?

  那麼我上面的問題(即我想使用新的api,但app又要支持舊的ios版本)怎麼解決? 組合!
  1. 我先判斷編譯環境, 以免低版本SDK不認識高版本SDK的api, 形成編譯錯誤(片斷1)
  2. 在高版本SDK的條件內, 自行開始判斷SDK版本, 或responedToSelector均可以,來判斷是否使用高版本的api
  3. 在低版本條件內, 直接用低版本的api

  片斷2的場景很明確了,只針對最低的sdk版本寫代碼,這樣使用你這個庫的用戶無論把deployment target設成幾,都是看不到錯誤的, 只是, 這就使得這種代碼執行起來, 永遠用的是最舊的API。

  SDWebImage 不支持iOS 5.0 如下的版本。

  SD_UIKIT 爲真時引入 <UIKit/UIKit.h>。

  SD_WATCH 爲真時引入 <WatchKit/WatchKit.h>。

參考連接:http://www.jianshu.com/p/9579b661d9f7

http://blog.csdn.net/kingsley_zhong/article/details/45919823

http://blog.csdn.net/xyxjn/article/details/40425895

原文連接:http://www.cnblogs.com/wfwenchao/articles/4861078.html?utm_source=tuicool&utm_medium=referral

   (七): NS_ENUM/NS_OPTIONS

1 #ifndef NS_ENUM
2 #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
3 #endif
4 
5 #ifndef NS_OPTIONS
6 #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
7 #endif

  Foundation 框架 -> NSObjCRuntime.h 裏面對NS_ENUM/NS_OPTIONS 的定義:

 1 /* NS_ENUM supports the use of one or two arguments. The first argument is always the integer type used for the values of the enum. The second argument is an optional type name for the macro. When specifying a type name, you must precede the macro with 'typedef' like so:
 2  
 3 typedef NS_ENUM(NSInteger, NSComparisonResult) {
 4     ...
 5 };
 6  
 7 If you do not specify a type name, do not use 'typedef'. For example:
 8  
 9 NS_ENUM(NSInteger) {
10     ...
11 };
12 */
13 #define NS_ENUM(...) CF_ENUM(__VA_ARGS__)
14 #define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name)

  參考: NS_ENUM/NS_OPTIONS 的區別

  (八): OS_OBJECT_USE_OBJC

  OS_OBJECT_USE_OBJC  這個宏時SDK 6.0 以後有的,usr/include -> os -> object.h 裏面對它的定義:

1 #ifndef OS_OBJECT_USE_OBJC
2 #define OS_OBJECT_USE_OBJC 1
3 #endif

  在 SDK 6.0 以前爲假,能夠用  (__IPHONE_OS_VERSION_MIN_REQUIRED < 60000)代替它。

 1 #if OS_OBJECT_USE_OBJC
 2     #undef SDDispatchQueueRelease
 3     #undef SDDispatchQueueSetterSementics
 4     #define SDDispatchQueueRelease(q)
 5     #define SDDispatchQueueSetterSementics strong
 6 #else
 7     #undef SDDispatchQueueRelease
 8     #undef SDDispatchQueueSetterSementics
 9     #define SDDispatchQueueRelease(q) (dispatch_release(q))
10     #define SDDispatchQueueSetterSementics assign
11 #endif

  這裏主要是針對GCD 的,GCD 中的對象在6.0以前是不參與ARC的,而6.0以後 在ARC下使用GCD不用關心釋放問題。

  對於最低sdk 版本 >= iOS 6.0來講,GCD 對象已經歸入了ARC 的管理範圍,咱們就不須要再手工調用 dispatch_release 了,不然的話,在sdk < 6.0的時候,即便咱們開啓了ARC ,這個宏OS_OBJECT_USE_OBJC 也是沒有的,也就是說這個時候,GCD對象還必須得本身管理。

   若是你開發的項目最低目標低於 iOS 6.0 or Mac OS X 10.8,你應該本身管理GCD對象,使用(dispatch_retain ,dispatch_release),ARC 並不會去管理它們。

   若是你開發的項目最低目標是 iOS 6.0 or Mac OS X 10.8 或者更高的,ARC 已經可以管理GCD 對象了,這時候,GCD 對象就如同普通的OC 對象同樣,不該該使用dispatch_retain , ordispatch_release 。 

參考連接: http://blog.csdn.net/chenyong05314/article/details/18863417

http://www.cnblogs.com/xzoscar/p/5145740.html

  (九): API

1 extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image);
2 
3 typedef void(^SDWebImageNoParamsBlock)();
4 
5 extern NSString *const SDWebImageErrorDomain;

 static int64_t kAsyncTestTimeout = 5;

   extern 參考連接: http://baike.baidu.com/link?url=rRSL-MltD7ZM0kBuf2D_BxTxs8FME1xxpVXRWswLMG2AN3Y6HuetZ82gr9MRL7w334heuATqYaJiDLH-Xav0EK

  extern 可置於變量或者函數前,以表示變量或者函數的定義在別的文件中,提示編譯器遇到此變量或函數時,在其它模塊中尋找其定義。另外,extern 也可用來進行連接指定。

  (十): dispatch_main_async_safe

1 #ifndef dispatch_main_async_safe
2 #define dispatch_main_async_safe(block)\
3     if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\
4         block();\
5     } else {\
6         dispatch_async(dispatch_get_main_queue(), block);\
7     }
8 #endif

  dispatch_queue_get_label(dispatch_queue_t _Nullable queue) 獲取參數queue 隊列的名字,若是隊列沒有名字,返回NULL。

  strcmp 字符串比較函數。

  宏 DISPATCH_CURRENT_QUEUE_LABEL 表明當前對列。

  dispatch_get_main_queue() 主隊列。

  獲取當前對列的名字和主對列的名字進行比較,若是相同表示當前就是主隊列,直接執行block() , 若是當前不是主隊列,使用

dispatch_async(dispatch_queue_t queue, dispatch_block_t block) 異步調用主隊列執行block() 。

  使用技巧:

  • 第一,咱們能夠像這樣在定義宏的時候使用換行,但須要添加 \ 操做符
  • 第二,若是當前線程已是主線程了,那麼在調用dispatch_async(dispatch_get_main_queue(), block)有可能會出現crash
  • 第三,若是當前線程是主線程,直接調用,若是不是,調用dispatch_async(dispatch_get_main_queue(), block)

   (十一): SDWebImageCompat.m

 1 #if !__has_feature(objc_arc)
 2     #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
 3 #endif
 4 
 5 // inline http://baike.baidu.com/link?url=HCLg60IJfwa55q1pfvZeHgUQ2g_kmN_jHSFlYWtHmDP2VgCL-rPcyzJ7b34fnyCIpMTP7mJex3_K7M7Vf14Czq
 6 
 7 inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) {
 8     if (!image) {
 9         return nil;
10     }
11     
12 #if SD_MAC // 若是是MAC 直接返回image
13     return image;
14     
15 #elif SD_UIKIT || SD_WATCH // 若是不是MAC 是 iOS TV 或者 WATCH
16     
17     if ((image.images).count > 0) { // 若是image.images.count 大於0
18         NSMutableArray<UIImage *> *scaledImages = [NSMutableArray array];
19         
20         for (UIImage *tempImage in image.images) {
21             [scaledImages addObject:SDScaledImageForKey(key, tempImage)];
22         }
23         
24         return [UIImage animatedImageWithImages:scaledImages duration:image.duration]; // 給 image 添加動畫並把image 返回
25     } else {
26         
27 #if SD_WATCH // 條件編譯 若是image.images.count 不大於0,且是WATCH的時候
28         if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) {
29 #elif SD_UIKIT // 條件編譯 若是image.images.count 不大於0,且是iOS 或者是TV 有UIKit.h 引入的時候
30             if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
31 #endif
32             
33                 CGFloat scale = 1;
34                 if (key.length >= 8) {
35                     NSRange range = [key rangeOfString:@"@2x."];
36                     if (range.location != NSNotFound) { // 若是是2倍圖
37                         scale = 2.0;
38                     }
39                     
40                     range = [key rangeOfString:@"@3x."];
41                     if (range.location != NSNotFound) { // 若是是3倍圖
42                         scale = 3.0;
43                     }
44                 }
45                 
46                 UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; // 建立scaledImage,並返回
47                 
48                 image = scaledImage;
49             }
50             return image;
51         }
52         
53 #endif
54     }
55     
56 NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain";

  UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) 是根據參數key 來調整圖片的scale。

  !__has_feature(objc_arc) SDWebImage 僅僅支持ARC 。

  inline: C++關鍵字,在函數聲明或定義中函數返回類型前加上關鍵字inline,便可以把函數指定爲內聯函數。關鍵字inline必須與函數定義放在一塊兒才能使函數成爲內聯,僅僅將inline放在函數聲明前面不起任何做用。inline是一種「用於實現的關鍵字」,而不是一種「用於聲明的關鍵字」。通常的,用戶能夠閱讀函數的聲明,可是看不到函數的定義。

   若是是在iOS/TV/WATCH 平臺下開發:

  若是 image.images.count 大於0,即image 是動效圖片,則對image.images 裏的每張圖片作遞歸處理,根據參數key 調整image.scale,並經過調用 + (nullable UIImage *)animatedImageWithImages:(NSArray<UIImage *> *)images duration:(NSTimeInterval)duration NS_AVAILABLE_IOS(5_0),返回一個調整過大小的新的動效圖片。

  若是 image.images.count 等於0,即image 是普通圖片, 根據參數key,調整圖片的scale,並返回調整過圖片大小的新的圖片。

 End

參考連接:http://www.jianshu.com/p/1d2e4d822732

相關文章
相關標籤/搜索