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查询数据库,并且获取获取相对路径,从而加载图片(这里注意一点,图片不是绝对路径保存,因为开发的沙盒的路径每次都会改变)。

上一篇下一篇

猜你喜欢

热点阅读