美文网首页
SDWebImage简易版

SDWebImage简易版

作者: tangbin583085 | 来源:发表于2017-11-12 14:04 被阅读0次

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

    相关文章

      网友评论

          本文标题:SDWebImage简易版

          本文链接:https://www.haomeiwen.com/subject/jeojmxtx.html