SDWebImage简易版
2017-11-12 本文已影响0人
tangbin583085
尝试书写简易版SDWebImage
在研究SDWebImage框架源代码之前还是先自己尝试书写了一个简易版的SDWebImage,很多原理和思路都是猜的,不知道正不正确,但是无论如何都学习到了很多知识和经验。
废话少说,说一下我实现UIImageView 加载网络图片实现的思路
1为UIImageView添加分类方法
增加的方法参考SDWebImage
- (void)tb_setImageWithURL:(nullable NSURL *)url;
- (void)tb_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder;
- (void)tb_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(TBWebImageOptions)options;
- (void)tb_setImageWithURL:(nullable NSURL *)url completed:(nullable TBExternalCompletionBlock)completedBlock;
- (void)tb_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable TBExternalCompletionBlock)completedBlock;
- (void)tb_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(TBWebImageOptions)options completed:(nullable TBExternalCompletionBlock)completedBlock;
并且利用运行时动态添加
@property (nonatomic, copy)ImageBlock imageBlock;
@property (nonatomic, copy)TBExternalCompletionBlock completionBlock;
为每次设置image或者结束运行时提供block运行。
2TBCoreWebImage(核心)
此类为核心类提供子线程请求加载网络图片,获取完之后回调给UIImageView。
@property (nonatomic, strong)NSOperationQueue *opQueue;
为每一张新的图片开辟子线程并且加入到opQueue
@property (nonatomic, strong)NSMutableDictionary *operationCache;
加每一次的子线程请求都加入到operationCache中。
@property (nonatomic, strong)NSMutableDictionary *imageCache;
加图片缓存到该字典中。
关键核心代码
- (void)url:(NSURL *)url targetView:(UIImageView *)targetView block:(void(^)(UIImage *image)) myBlock option:(TBWebImageOptions)option completedBlock:(TBExternalCompletionBlock)completionBlock{
// 移除view
[self.waitForImage enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSMutableArray<UIImageView *> * _Nonnull obj, BOOL * _Nonnull stop) {
[obj removeObject:targetView];
}];
// 如果缓存有,就直接返回
if (self.imageCache[url.absoluteString]) {
!myBlock? : myBlock(self.imageCache[url.absoluteString]);
!completionBlock? : completionBlock(self.imageCache[url.absoluteString], nil, url);
return;
}else {// 去数据库获取缓存数据
TBDBTool *tool = [TBDBTool shareInstance];
UIImage *dbImageCache = [tool image:url.absoluteString];
if (dbImageCache) {
self.imageCache[url.absoluteString] = dbImageCache;
!myBlock? : myBlock(self.imageCache[url.absoluteString]);
!completionBlock? : completionBlock(self.imageCache[url.absoluteString], nil, url);
return;
}
}
// 网络数据
if (self.operationCache[url.absoluteString]) {// 正在处理中
}else {
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
int delay = arc4random() % 10;
[NSThread sleepForTimeInterval:delay];
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfURL:url options:NSDataReadingMappedIfSafe error:&error];
UIImage *image = [UIImage imageWithData:data];
// 缓存并执行目标array所有block
if (image) {
// 保存到数据库
TBDBTool *tool = [TBDBTool shareInstance];
[tool saveImage:url.absoluteString image:image];
[self.imageCache setValue:image forKey:url.absoluteString];
NSMutableArray<UIImageView *> *array = self.waitForImage[url.absoluteString];
for (UIImageView *imageView in array) {
dispatch_sync(dispatch_get_main_queue(), ^{
!imageView.imageBlock? : imageView.imageBlock(image);
!imageView.completionBlock? : imageView.completionBlock(image, error, url);
});
}
[array removeAllObjects];
}else if(error && (option & TBWebImageRetryFailed)) {// 发生错误就重试一次
[self tryWhenError:url];
}
// 移除执行缓存
[self.operationCache removeObjectForKey:url];
}];
// 保存缓存
self.operationCache[url.absoluteString] = operation;
[self.opQueue addOperation:operation];
}
NSMutableArray<UIImageView *> *array = self.waitForImage[url.absoluteString];
if (array == nil) {
array = [NSMutableArray array];
self.waitForImage[url.absoluteString] = array;
}
[array addObject:targetView];
}
3图片保存到本地并且记录到数据库
TBDBTool该类提供保存和获取图片到沙盒
- (BOOL)saveImage:(NSString *)url image:(UIImage *)image;
根据url将图片对象保存至沙盒中,并且记录到数据库
- (UIImage *)image:(NSString *)url;
根据url查询数据库,并且获取获取相对路径,从而加载图片(这里注意一点,图片不是绝对路径保存,因为开发的沙盒的路径每次都会改变)。