SDWebImage源码注解(转载)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
/*
*ThisfileispartoftheSDWebImagepackage.
*(c)OlivierPoitrey*
*Forthefullcopyrightandlicenseinformation,pleaseviewtheLICENSE
*filethatwasdistributedwiththissourcecode.
*/
#import"SDWebImageCompat.h"
#import"SDWebImageOperation.h"
#import"SDWebImageDownloader.h"
#import"SDImageCache.h"
typedefNS_OPTIONS(NSUInteger,SDWebImageOptions){
/**
*Bydefault,whenaURLfailtobedownloaded,theURLisblacklistedsothelibrarywon'tkeeptrying.
*Thisflagdisablethisblacklisting.
*/
/**
*默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他.)
*/
SDWebImageRetryFailed=1<<0,
/**
*Bydefault,imagedownloadsarestartedduringUIinteractions,thisflagsdisablethisfeature,
*leadingtodelayeddownloadonUIScrollViewdecelerationforinstance.
*/
/**
*默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候
*才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片)
*/
SDWebImageLowPriority=1<<1,
/**
*Thisflagdisableson-diskcaching
*/
/*
*这个flag禁止磁盘缓存,只有内存缓存
*/
SDWebImageCacheMemoryOnly=1<<2,
/**
*Thisflagenablesprogressivedownload,theimageisdisplayedprogressivelyduringdownloadasabrowserwoulddo.
*Bydefault,theimageisonlydisplayedoncecompletelydownloaded.
*/
/*
*这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
*
*/
SDWebImageProgressiveDownload=1<<3,
/**
*Eveniftheimageiscached,respecttheHTTPresponsecachecontrol,andrefreshtheimagefromremotelocationifneeded.
*ThediskcachingwillbehandledbyNSURLCacheinsteadofSDWebImageleadingtoslightperformancedegradation.
*ThisoptionhelpsdealwithimageschangingbehindthesamerequestURL,e.g.Facebookgraphapiprofilepics.
*Ifacachedimageisrefreshed,thecompletionblockiscalledoncewiththecachedimageandagainwiththefinalimage.
*
*Usethisflagonlyifyoucan'tmakeyourURLsstaticwithembededcachebustingparameter.
*/
/*
*这个选项的意思看的不是很懂,大意是即使一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.
*
*/
SDWebImageRefreshCached=1<<4,
/**
*IniOS4+,continuethedownloadoftheimageiftheappgoestobackground.Thisisachievedbyaskingthesystemfor
*extratimeinbackgroundtolettherequestfinish.Ifthebackgroundtaskexpirestheoperationwillbecancelled.
*/
/*
*启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
*/
SDWebImageContinueInBackground=1<<5,
/**
*HandlescookiesstoredinNSHTTPCookieStorebysetting
*NSMutableURLRequest.HTTPShouldHandleCookies=YES;
*/
/*
*可以控制存在NSHTTPCookieStore的cookies.(我没用过,等用过的人过来解释一下)
*/
SDWebImageHandleCookies=1<<6,
/**
*EnabletoallowuntrustedSSLceriticates.
*Usefulfortestingpurposes.Usewithcautioninproduction.
*/
/*
*允许不安全的SSL证书,在正式环境中慎用
*/
SDWebImageAllowInvalidSSLCertificates=1<<7,
/**
*Bydefault,imageareloadedintheordertheywerequeued.Thisflagmovethemto
*thefrontofthequeueandisloadedimmediatelyinsteadofwaitingforthecurrentqueuetobeloaded(which
*couldtakeawhile).
*/
/*
*默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载
*而不是等到当前队列装载的时候再装载.
*/
SDWebImageHighPriority=1<<8,
/**
*Bydefault,placeholderimagesareloadedwhiletheimageisloading.Thisflagwilldelaytheloading
*oftheplaceholderimageuntilaftertheimagehasfinishedloading.
*/
/*
*默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.(等图片显示完了我干嘛还显示占位图?或许是我理解错了?)
*/
SDWebImageDelayPlaceholder=1<<9,
/**
*Weusuallydon'tcalltransformDownloadedImagedelegatemethodonanimatedimages,
*asmosttransformationcodewouldmangleit.
*Usethisflagtotransformthemanyway.
*/
/*
*是否transform图片(没用过,还要再看,但是据我估计,是否是图片有可能方向不对需要调整方向,例如采用iPhone拍摄的照片如果不纠正方向,那么图片是向左旋转90度的.可能很多人不知道iPhone的摄像头并不是竖直的,而是向左偏了90度.具体请google.)
*/
SDWebImageTransformAnimatedImage=1<<10,
};
typedefvoid(^SDWebImageCompletionBlock)(UIImage*image,NSError*error,SDImageCacheTypecacheType,NSURL*imageURL);
typedefvoid(^SDWebImageCompletionWithFinishedBlock)(UIImage*image,NSError*error,SDImageCacheTypecacheType,BOOLfinished,NSURL*imageURL);
typedefNSString*(^SDWebImageCacheKeyFilterBlock)(NSURL*url);
@classSDWebImageManager;
@protocolSDWebImageManagerDelegate@optional
/**
*Controlswhichimageshouldbedownloadedwhentheimageisnotfoundinthecache.
*
*@paramimageManagerThecurrent`SDWebImageManager`
*@paramimageURLTheurloftheimagetobedownloaded
*
*@returnReturnNOtopreventthedownloadingoftheimageoncachemisses.Ifnotimplemented,YESisimplied.
*/
/*
*主要作用是当缓存里没有发现某张图片的缓存时,是否选择下载这张图片(默认是yes),可以选择no,那么sdwebimage在缓存中没有找到这张图片的时候不会选择下载
*/
-(BOOL)imageManager:(SDWebImageManager*)imageManagershouldDownloadImageForURL:(NSURL*)imageURL;
/**
*Allowstotransformtheimageimmediatelyafterithasbeendownloadedandjustbeforetocacheitondiskandmemory.
*NOTE:Thismethodiscalledfromaglobalqueueinordertonottoblockthemainthread.
*
*@paramimageManagerThecurrent`SDWebImageManager`
*@paramimageTheimagetotransform
*@paramimageURLTheurloftheimagetotransform
*
*@returnThetransformedimageobject.
*/
/**
*在图片下载完成并且还没有加入磁盘缓存或者内存缓存的时候就transform这个图片.这个方法是在异步线程执行的,防治阻塞主线程.
*至于为什么在异步执行很简单,对一张图片纠正方向(也就是transform)是很耗资源的,一张2M大小的图片纠正方向你可以用instrument测试一下耗时.
*很恐怖
*/
-(UIImage*)imageManager:(SDWebImageManager*)imageManagertransformDownloadedImage:(UIImage*)imagewithURL:(NSURL*)imageURL;
@end
/**
*TheSDWebImageManageristheclassbehindtheUIImageView+WebCachecategoryandlikes.
*Ittiestheasynchronousdownloader(SDWebImageDownloader)withtheimagecachestore(SDImageCache).
*Youcanusethisclassdirectlytobenefitfromwebimagedownloadingwithcachinginanothercontextthan
*aUIView.
*
*HereisasimpleexampleofhowtouseSDWebImageManager:
*
*@code
SDWebImageManager*manager=[SDWebImageManagersharedManager];
[managerdownloadImageWithURL:imageURL
options:0
progress:nil
completed:^(UIImage*image,NSError*error,SDImageCacheTypecacheType,BOOLfinished,NSURL*imageURL){
if(image){
//dosomethingwithimage
}
}];
*@endcode
*/
/*
*这一段是阐述SDWebImageManager是干嘛的.其实UIImageView+WebCache这个category背后执行操作的就是这个SDWebImageManager.他会绑定一个下载器也就是SDWebImageDownloader和一个缓存SDImageCache.后面的大意应该是讲你可以直接使用一个其他上下文环境的SDWebImageManager,而不是仅仅限于一个UIView.
*/
@interfaceSDWebImageManager:NSObject
@property(weak,nonatomic)iddelegate;
/**
*如同上文所说,一个SDWebImageManager会绑定一个imageCache和一个下载器.
*/
@property(strong,nonatomic,readonly)SDImageCache*imageCache;
@property(strong,nonatomic,readonly)SDWebImageDownloader*imageDownloader;
/**
*ThecachefilterisablockusedeachtimeSDWebImageManagerneedtoconvertanURLintoacachekey.Thiscan
*beusedtoremovedynamicpartofanimageURL.
*
*Thefollowingexamplesetsafilterintheapplicationdelegatethatwillremoveanyquery-stringfromthe
*URLbeforetouseitasacachekey:
*
*@code
[[SDWebImageManagersharedManager]setCacheKeyFilter:^(NSURL*url){
url=[[NSURLalloc]initWithScheme:url.schemehost:url.hostpath:url.path];
return[urlabsoluteString];
}];
*@endcode
*/
/*
*这个cacheKeyFilter是干嘛的呢?很简单.1他是一个block.2.这个block的作用就是生成一个image的key.因为sdwebimage的缓存原理你可以当成是一个字典,每一个字典的value就是一张image,那么这个value对应的key是什么呢?就是cacheKeyFilter根据某个规则对这个图片的url做一些操作生成的.上面的示例就显示了怎么利用这个block把image的url重新组合生成一个key.以后当sdwebimage检测到你
*/
@property(nonatomic,copy)SDWebImageCacheKeyFilterBlockcacheKeyFilter;
/**
*ReturnsglobalSDWebImageManagerinstance.
*
*@returnSDWebImageManagersharedinstance
*/
/*
*这个不用我解释了吧,生成一个SDWebImagemanager的单例.
*/
+(SDWebImageManager*)sharedManager;
/**
*DownloadstheimageatthegivenURLifnotpresentincacheorreturnthecachedversionotherwise.
*从给定的URL中下载一个之前没有被缓存的Image.
*
*@paramurlTheURLtotheimage
*@paramoptionsAmasktospecifyoptionstouseforthisrequest
*@paramprogressBlockAblockcalledwhileimageisdownloading
*@paramcompletedBlockAblockcalledwhenoperationhasbeencompleted.
*
*Thisparameterisrequired.
*
*ThisblockhasnoreturnvalueandtakestherequestedUIImageasfirstparameter.
*IncaseoferrortheimageparameterisnilandthesecondparametermaycontainanNSError.
*
*Thethirdparameterisan`SDImageCacheType`enumindicatingiftheimagewasretrivedfromthelocalcache
*orfromthememorycacheorfromthenetwork.
*
*ThelastparameterissettoNOwhentheSDWebImageProgressiveDownloadoptionisusedandtheimageis
*downloading.Thisblockisthuscalledrepetidlywithapartialimage.Whenimageisfullydownloaded,the
*blockiscalledalasttimewiththefullimageandthelastparametersettoYES.
*
*@returnReturnsanNSObjectconformingtoSDWebImageOperation.ShouldbeaninstanceofSDWebImageDownloaderOperation
*/
/*
*这个方法主要就是SDWebImage下载图片的方法了.
*第一个参数是必须要的,就是image的url
*第二个参数就是我们上面的Options,你可以定制化各种各样的操作.详情参上.
*第三个参数是一个回调block,用于图片在下载过程中的回调.(英文注释应该是有问题的.)
*第四个参数是一个下载完成的回调.会在图片下载完成后回调.
*返回值是一个NSObject类,并且这个NSObject类是conforming一个协议这个协议叫做SDWebImageOperation,这个协议很简单,就是一个cancel掉operation的协议.
*/
-(id)downloadImageWithURL:(NSURL*)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
/**
*SavesimagetocacheforgivenURL
*
*@paramimageTheimagetocache
*@paramurlTheURLtotheimage
*
*/
/*
*将图片存入cache的方法,类似于字典的setValue:forKey:
*/
-(void)saveImageToCache:(UIImage*)imageforURL:(NSURL*)url;
/**
*Cancelallcurrentopreations
*/
/*
*取消掉当前所有的下载图片的operation
*/
-(void)cancelAll;
/**
*Checkoneormoreoperationsrunning
*/
/*
*check一下是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
*/
-(BOOL)isRunning;
/**
*Checkifimagehasalreadybeencached
*
*@paramurlimageurl
*
*@returniftheimagewasalreadycached
*/
/*
*通过一个image的url是否已经存在,如果存在返回yes,否则返回no
*/
-(BOOL)cachedImageExistsForURL:(NSURL*)url;
/**
*Checkifimagehasalreadybeencachedondiskonly
*
*@paramurlimageurl
*
*@returniftheimagewasalreadycached(diskonly)
*/
/*
*检测一个image是否已经被缓存到磁盘(是否存且仅存在disk里).
*/
-(BOOL)diskImageExistsForURL:(NSURL*)url;
/**
*Asynccheckifimagehasalreadybeencached
*
*@paramurlimageurl
*@paramcompletionBlocktheblocktobeexecutedwhenthecheckisfinished
*
*@notethecompletionblockisalwaysexecutedonthemainqueue
*/
/*
*如果检测到图片已经被缓存,那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
*/
-(void)cachedImageExistsForURL:(NSURL*)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
*Asynccheckifimagehasalreadybeencachedondiskonly
*
*@paramurlimageurl
*@paramcompletionBlocktheblocktobeexecutedwhenthecheckisfinished
*
*@notethecompletionblockisalwaysexecutedonthemainqueue
*/
/*
*如果检测到图片已经被缓存在磁盘(存且仅存在disk),那么执行回调block.这个block会永远执行在主线程.也就是你可以在这个回调block里更新ui.
*/
-(void)diskImageExistsForURL:(NSURL*)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
*ReturnthecachekeyforagivenURL
*/
/*
*通过image的url返回image存在缓存里的key.有人会问了,为什么不直接把图片的url当做image的key来使用呢?而是非要对url做一些处理才能当做key.我的解释是,我也不太清楚.可能为了防止重复吧.
*/
-(NSString*)cacheKeyForURL:(NSURL*)url;
@end
#pragmamark-Deprecated
typedefvoid(^SDWebImageCompletedBlock)(UIImage*image,NSError*error,SDImageCacheTypecacheType)__deprecated_msg( "Blocktypedeprecated.Use`SDWebImageCompletionBlock`" );
typedefvoid(^SDWebImageCompletedWithFinishedBlock)(UIImage*image,NSError*error,SDImageCacheTypecacheType,BOOLfinished)__deprecated_msg( "Blocktypedeprecated.Use`SDWebImageCompletionWithFinishedBlock`" );
//已被废弃
@interfaceSDWebImageManager(Deprecated)
/**
*DownloadstheimageatthegivenURLifnotpresentincacheorreturnthecachedversionotherwise.
*
*@deprecatedThismethodhasbeendeprecated.Use`downloadImageWithURL:options:progress:completed:`
*/
-(id)downloadWithURL:(NSURL*)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletedWithFinishedBlock)completedBlock__deprecated_msg( "Methoddeprecated.Use`downloadImageWithURL:options:progress:completed:`" );
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
/*
*ThisfileispartoftheSDWebImagepackage.
*(c)OlivierPoitrey*
*Forthefullcopyrightandlicenseinformation,pleaseviewtheLICENSE
*filethatwasdistributedwiththissourcecode.
*/
#import"SDWebImageManager.h"
#import//内部类.
@interfaceSDWebImageCombinedOperation:NSObject@property(assign,nonatomic,getter=isCancelled)BOOLcancelled;
@property(copy,nonatomic)SDWebImageNoParamsBlockcancelBlock;
@property(strong,nonatomic)NSOperation*cacheOperation;
@end
@interfaceSDWebImageManager()
@property(strong,nonatomic,readwrite)SDImageCache*imageCache;
@property(strong,nonatomic,readwrite)SDWebImageDownloader*imageDownloader;
@property(strong,nonatomic)NSMutableSet*failedURLs;
@property(strong,nonatomic)NSMutableArray*runningOperations;
@end
@implementationSDWebImageManager
//利用disptach_once特性生成一个单例,用烂了的方法.不赘述.
+(id)sharedManager{
staticdispatch_once_tonce;
staticidinstance;
dispatch_once(&once,^{
instance=[self new ];
});
return instance;
}
//初始化方法.
//1.获得一个SDImageCache的单例.2.获取一个SDWebImageDownloader的单例.3.新建一个MutableSet来存储下载失败的url.
//4.新建一个用来存储下载operation的可变数组.
//为什么不用MutableArray储存下载失败的URL?
//因为NSSet类有一个特性,就是Hash.实际上NSSet是一个哈希表,哈希表比数组优秀的地方是什么呢?就是查找速度快.查找同样一个元素,哈希表只需要通过key
//即可取到,而数组至少需要遍历依次.因为SDWebImage里有关失败URL的业务需求是,一个失败的URL只需要储存一次.这样的话Set自然比Array更合适.
-(id)init{
if ((self=[ super init])){
_imageCache=[selfcreateCache];
_imageDownloader=[SDWebImageDownloadersharedDownloader];
_failedURLs=[NSMutableSet new ];
_runningOperations=[NSMutableArray new ];
}
return self;
}
//获取一个cache的单例
-(SDImageCache*)createCache{
return [SDImageCachesharedImageCache];
}
//利用Image的URL生成一个缓存时需要的key.
//这里有两种情况,第一种是如果检测到cacheKeyFilter不为空时,利用cacheKeyFilter来处理URL生成一个key.
//如果为空,那么直接返回URL的string内容,当做key.
-(NSString*)cacheKeyForURL:(NSURL*)url{
if (self.cacheKeyFilter){
return self.cacheKeyFilter(url);
}
else {
return [urlabsoluteString];
}
}
//检测一张图片是否已被缓存.
//首先检测内存缓存是否存在这张图片,如果已有,直接返回yes.
//如果内存缓存里没有这张图片,那么调用diskImageExistsWithKey这个方法去硬盘缓存里找
-(BOOL)cachedImageExistsForURL:(NSURL*)url{
NSString*key=[selfcacheKeyForURL:url];
if ([self.imageCacheimageFromMemoryCacheForKey:key]!=nil) return YES;
return [self.imageCachediskImageExistsWithKey:key];
}
//检测硬盘里是否缓存了图片
-(BOOL)diskImageExistsForURL:(NSURL*)url{
NSString*key=[selfcacheKeyForURL:url];
return [self.imageCachediskImageExistsWithKey:key];
}
//首先生成一个用来cache住Image的key(利用key的url生成)
//然后检测内存缓存里是否已经有这张图片
//如果已经被缓存,那么再主线程里回调block
//如果没有检测到,那么调用diskImageExistsWithKey,这个方法会在异步线程里,将图片存到硬盘,当然在存图之前也会检测是否已在硬盘缓存图片.
-(void)cachedImageExistsForURL:(NSURL*)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock{
NSString*key=[selfcacheKeyForURL:url];
BOOLisInMemoryCache=([self.imageCacheimageFromMemoryCacheForKey:key]!=nil);
if (isInMemoryCache){
//makingsurewecallthecompletionblockonthemainqueue
dispatch_async(dispatch_get_main_queue(),^{
if (completionBlock){
completionBlock(YES);
}
});
return ;
}
[self.imageCachediskImageExistsWithKey:keycompletion:^(BOOLisInDiskCache){
//thecompletionblockofcheckDiskCacheForImageWithKey:completion:isalwayscalledonthemainqueue,noneedtofurtherdispatch
if (completionBlock){
completionBlock(isInDiskCache);
}
}];
}
//将图片存入硬盘
-(void)diskImageExistsForURL:(NSURL*)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock{
NSString*key=[selfcacheKeyForURL:url];
[self.imageCachediskImageExistsWithKey:keycompletion:^(BOOLisInDiskCache){
//thecompletionblockofcheckDiskCacheForImageWithKey:completion:isalwayscalledonthemainqueue,noneedtofurtherdispatch
if (completionBlock){
completionBlock(isInDiskCache);
}
}];
}
//通过url建立一个operation用来下载图片.
-(id)downloadImageWithURL:(NSURL*)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock{
//InvokingthismethodwithoutacompletedBlockispointless
NSAssert(completedBlock!=nil,@ "Ifyoumeantoprefetchtheimage,use-[SDWebImagePrefetcherprefetchURLs]instead" );
//VerycommonmistakeistosendtheURLusingNSStringobjectinsteadofNSURL.Forsomestrangereason,XCodewon't
//throwanywarningforthistypemismatch.HerewefailsafethiserrorbyallowingURLstobepassedasNSString.
if ([urlisKindOfClass:NSString.class]){
url=[NSURLURLWithString:(NSString*)url];
}
//PreventsappcrashingonargumenttypeerrorlikesendingNSNullinsteadofNSURL
if (![urlisKindOfClass:NSURL.class]){
url=nil;
}
__blockSDWebImageCombinedOperation*operation=[SDWebImageCombinedOperation new ];
__weakSDWebImageCombinedOperation*weakOperation=operation;
BOOLisFailedUrl=NO;
//创建一个互斥锁防止现在有别的线程修改failedURLs.
//判断这个url是否是fail过的.如果urlfailed过的那么isFailedUrl就是true
@synchronized(self.failedURLs){
isFailedUrl=[self.failedURLscontainsObject:url];
}
//如果url不存在那么直接返回一个block,如果url存在.那么继续进行判断.
//options与SDWebImageRetryFailed这个option进行按位与操作.判断用户的options里是否有retry这个option.
//如果用户的options里没有retry这个选项并且isFaileUrl是true.那么就回调一个error的block.
if (!url||(!(options&SDWebImageRetryFailed)&&isFailedUrl)){
dispatch_main_sync_safe(^{
NSError*error=[NSErrorerrorWithDomain:NSURLErrorDomaincode:NSURLErrorFileDoesNotExistuserInfo:nil];
completedBlock(nil,error,SDImageCacheTypeNone,YES,url);
});
return operation;
}
//创建一个互斥锁防止现在有别的线程修改runningOperations.
@synchronized(self.runningOperations){
[self.runningOperationsaddObject:operation];
}
NSString*key=[selfcacheKeyForURL:url];
//cacheOperation应该是一个用来下载图片并且缓存的operation
operation.cacheOperation=[self.imageCachequeryDiskCacheForKey:keydone:^(UIImage*image,SDImageCacheTypecacheType){
//判断operation这时候有没有执行cancel操作,如果cancel掉了就把这个operation从我们的operation数组里remove掉然后return
if (operation.isCancelled){
@synchronized(self.runningOperations){
[self.runningOperationsremoveObject:operation];
}
return ;
}
if ((!image||options&SDWebImageRefreshCached)&&(![self.delegaterespondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)]||[self.delegateimageManager:selfshouldDownloadImageForURL:url])){
if (image&&options&SDWebImageRefreshCached){
dispatch_main_sync_safe(^{
//IfimagewasfoundinthecachebugSDWebImageRefreshCachedisprovided,notifyaboutthecachedimage
//ANDtrytore-downloaditinordertoletachancetoNSURLCachetorefreshitfromserver.
completedBlock(image,nil,cacheType,YES,url);
});
}
//downloadifnoimageorrequestedtorefreshanyway,anddownloadallowedbydelegate
//下面都是判断我们的options里包含哪些SDWebImageOptions,然后给我们的downloaderOptions相应的添加对应的SDWebImageDownloaderOptions.downloaderOptions|=SDWebImageDownloaderLowPriority这种表达式的意思等同于
//downloaderOptions=downloaderOptions|SDWebImageDownloaderLowPriority
SDWebImageDownloaderOptionsdownloaderOptions=0;
if (options&SDWebImageLowPriority)downloaderOptions|=SDWebImageDownloaderLowPriority;
if (options&SDWebImageProgressiveDownload)downloaderOptions|=SDWebImageDownloaderProgressiveDownload;
if (options&SDWebImageRefreshCached)downloaderOptions|=SDWebImageDownloaderUseNSURLCache;
if (options&SDWebImageContinueInBackground)downloaderOptions|=SDWebImageDownloaderContinueInBackground;
if (options&SDWebImageHandleCookies)downloaderOptions|=SDWebImageDownloaderHandleCookies;
if (options&SDWebImageAllowInvalidSSLCertificates)downloaderOptions|=SDWebImageDownloaderAllowInvalidSSLCertificates;
if (options&SDWebImageHighPriority)downloaderOptions|=SDWebImageDownloaderHighPriority;
if (image&&options&SDWebImageRefreshCached){
//forceprogressiveoffifimagealreadycachedbutforcedrefreshing
downloaderOptions&=~SDWebImageDownloaderProgressiveDownload;
//ignoreimagereadfromNSURLCacheifimageifcachedbutforcerefreshing
downloaderOptions|=SDWebImageDownloaderIgnoreCachedResponse;
}
//调用imageDownloader去下载image并且返回执行这个request的download的operation
idsubOperation=[self.imageDownloaderdownloadImageWithURL:urloptions:downloaderOptionsprogress:progressBlockcompleted:^(UIImage*downloadedImage,NSData*data,NSError*error,BOOLfinished){
if (weakOperation.isCancelled){
//Donothingiftheoperationwascancelled
//See#699formoredetails
//ifwewouldcallthecompletedBlock,therecouldbearaceconditionbetweenthisblockandanothercompletedBlockforthesameobject,soifthisoneiscalledsecond,wewilloverwritethenewdata
}
else if (error){
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled){
completedBlock(nil,error,SDImageCacheTypeNone,finished,url);
}
});
if (error.code!=NSURLErrorNotConnectedToInternet&&error.code!=NSURLErrorCancelled&&error.code!=NSURLErrorTimedOut){
@synchronized(self.failedURLs){
[self.failedURLsaddObject:url];
}
}
}
else {
if ((options&SDWebImageRetryFailed)){
@synchronized(self.failedURLs){
[self.failedURLsremoveObject:url];
}
}
BOOLcacheOnDisk=!(options&SDWebImageCacheMemoryOnly);
if (options&SDWebImageRefreshCached&&image&&!downloadedImage){
//ImagerefreshhittheNSURLCachecache,donotcallthecompletionblock
}
else if (downloadedImage&&(!downloadedImage.images||(options&SDWebImageTransformAnimatedImage))&&[self.delegaterespondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0),^{
UIImage*transformedImage=[self.delegateimageManager:selftransformDownloadedImage:downloadedImagewithURL:url];
if (transformedImage&&finished){
BOOLimageWasTransformed=![transformedImageisEqual:downloadedImage];
[self.imageCachestoreImage:transformedImagerecalculateFromImage:imageWasTransformedimageData:dataforKey:keytoDisk:cacheOnDisk];
}
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled){
completedBlock(transformedImage,nil,SDImageCacheTypeNone,finished,url);
}
});
});
}
else {
if (downloadedImage&&finished){
[self.imageCachestoreImage:downloadedImagerecalculateFromImage:NOimageData:dataforKey:keytoDisk:cacheOnDisk];
}
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled){
completedBlock(downloadedImage,nil,SDImageCacheTypeNone,finished,url);
}
});
}
}
if (finished){
@synchronized(self.runningOperations){
[self.runningOperationsremoveObject:operation];
}
}
}];
operation.cancelBlock=^{
[subOperationcancel];
@synchronized(self.runningOperations){
[self.runningOperationsremoveObject:weakOperation];
}
};
}
else if (image){
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled){
completedBlock(image,nil,cacheType,YES,url);
}
});
@synchronized(self.runningOperations){
[self.runningOperationsremoveObject:operation];
}
}
else {
//Imagenotincacheanddownloaddisallowedbydelegate
dispatch_main_sync_safe(^{
if (!weakOperation.isCancelled){
completedBlock(nil,nil,SDImageCacheTypeNone,YES,url);
}
});
@synchronized(self.runningOperations){
[self.runningOperationsremoveObject:operation];
}
}
}];
return operation;
}
-(void)saveImageToCache:(UIImage*)imageforURL:(NSURL*)url{
if (image&&url){
NSString*key=[selfcacheKeyForURL:url];
[self.imageCachestoreImage:imageforKey:keytoDisk:YES];
}
}
//cancel掉所有正在执行的operation
-(void)cancelAll{
@synchronized(self.runningOperations){
NSArray*copiedOperations=[self.runningOperationscopy];
[copiedOperationsmakeObjectsPerformSelector:@selector(cancel)];
[self.runningOperationsremoveObjectsInArray:copiedOperations];
}
}
//判断是否有正在运行的operation
-(BOOL)isRunning{
return self.runningOperations.count>0;
}
@end
@implementationSDWebImageCombinedOperation
-(void)setCancelBlock:(SDWebImageNoParamsBlock)cancelBlock{
//checkiftheoperationisalreadycancelled,thenwejustcallthecancelBlock
if (self.isCancelled){
if (cancelBlock){
cancelBlock();
}
_cancelBlock=nil; //don'tforgettonilthecancelBlock,otherwisewewillgetcrashes
} else {
_cancelBlock=[cancelBlockcopy];
}
}
-(void)cancel{
self.cancelled=YES;
if (self.cacheOperation){
[self.cacheOperationcancel];
self.cacheOperation=nil;
}
if (self.cancelBlock){
self.cancelBlock();
//TODO:thisisatemporaryfixto#809.
//Untilwecanfiguretheexactcauseofthecrash,goingwiththeivarinsteadofthesetter
//self.cancelBlock=nil;
_cancelBlock=nil;
}
}
@end
@implementationSDWebImageManager(Deprecated)
//deprecatedmethod,usesthenondeprecatedmethod
//adapterforthecompletionblock
-(id)downloadWithURL:(NSURL*)urloptions:(SDWebImageOptions)optionsprogress:(SDWebImageDownloaderProgressBlock)progressBlockcompleted:(SDWebImageCompletedWithFinishedBlock)completedBlock{
return [selfdownloadImageWithURL:url
options:options
progress:progressBlock
completed:^(UIImage*image,NSError*error,SDImageCacheTypecacheType,BOOLfinished,NSURL*imageURL){
if (completedBlock){
completedBlock(image,error,cacheType,finished);
}
}];
}
@end

下面来简单的解释一下OC里枚举的两种类型.

NS_ENUM和NS_OPTIONS

本质上是一样的都是枚举.

我举个例子.

1
2
3
4
5
6
7
typedefNS_ENUM(NSInteger,UIViewAnimationTransition){
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
1
2
3
4
5
6
7
8
9
typedefNS_OPTIONS(NSUInteger,UIViewAutoresizing){
UIViewAutoresizingNone=0,
UIViewAutoresizingFlexibleLeftMargin=1<<0,
UIViewAutoresizingFlexibleWidth=1<<1,
UIViewAutoresizingFlexibleRightMargin=1<<2,
UIViewAutoresizingFlexibleTopMargin=1<<3,
UIViewAutoresizingFlexibleHeight=1<<4,
UIViewAutoresizingFlexibleBottomMargin=1<<5
};

应该可以看出一些苗头.

NS_ENUM这种声明出来的东西大部分是单选. NS_OPTIONS声明出来的大部分是多选.

像UIViewAnimationTransition这种在用的时候肯定是只能选一种效果,你要么从左翻到右,要么从右翻到左,你做动画的时候总不能同一时刻让他同时从左到右,又从右到左翻,对吧.

而UIViewAutosizing就不一样了.我要是让子view的宽高和父View一样,那么autoviewsizing的选项肯定是类似于这种.UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight

没错吧,意思就是两个options的我都得选才行.

那么如果有个场景让我判断当前的view的Autoresizing有哪几个.我怎么判断呢?

很简单.用按位与操作就行了.

假设 autoResizings = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;

我们判断autoResizings里是否有UIViewAutoresizingFlexibleLeftMargin的时候只需要if(autoResizings & UIViewAutoresizingFlexibleLeftMargin)是否为true就可以了.

用二进制表示的话(这里不用care NSUInteger到底是几位的.就表示这么个意思)

1
2
3
UIViewAutoresizingFlexibleLeftMargin=00000001
UIViewAutoresizingFlexibleWidth=00000010
UIViewAutoresizingFlexibleRightMargin=00000100

所以根据上面的表达式,我们的autoResizings = 00000111.

那么执行按位与操作是这样的.

1
2
3
00000111
&00000001
结果就是00000001,为 true .表示含有这个选项.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值