SDWebImage源码(一)

322 阅读4分钟

@(Third-Library Set)[SDWebImage, SDWebImageDownloaderOperation] #SDWebImage(一) SDWebImageDownloaderOperation [TOC] ##代码规范

###实例变量的初始化 代码规范这里涉及到一些官方文档提到的东西.比如说: 在内存优化管理中提到的,在初始化dealloc中不要使用访问器方法,也就是setter或者getter.也可以理解为就是语法糖(点语法).有如下代码:

- (id)initWithRequest:(NSURLRequest *)request
            inSession:(NSURLSession *)session
              options:(SDWebImageDownloaderOptions)options
             progress:(SDWebImageDownloaderProgressBlock)progressBlock
            completed:(SDWebImageDownloaderCompletedBlock)completedBlock
            cancelled:(SDWebImageNoParamsBlock)cancelBlock {
    if ((self = [super init])) {
        _request = [request copy];
        _shouldDecompressImages = YES;
        _options = options;
        _progressBlock = [progressBlock copy]; //因为是传递进来的,所以进行一次copy操作.
        _completedBlock = [completedBlock copy];
        _cancelBlock = [cancelBlock copy];
        _executing = NO;
        _finished = NO;
        _expectedSize = 0;
        _unownedSession = session;
        responseFromCached = YES; // Initially wrong until `- URLSession:dataTask:willCacheResponse:completionHandler: is called or not called
    }
    return self;
}

可以看到用的都是带下划线的实例变量.当然这不是一定要这样,视情况而定吧.

###继承NSOperation要遵守的一些规则. 如果没有阅读过关于NSOperation开发的一些文档,那么我们很可能会忽略一些东西.比如说一些对于并发的operations,需要重写一些方法: isExecuting, isFinished, isConcurrent等等; 例如需要在改变executingfinished变量的值时,调用willChangeValueForKey:, didChangeValueForKey:这些方法; 还有在合适的时机需要去调用isCancelled,来判断当前操作是否被取消了等等. SD中都遵守了这样的规则.在自己写代码的时候,也需要注意这些.

##后台执行任务 SD只是重写了start方法,并没有重写main方法,这点不太理解. 其在start中,设置了当程序退到后台的时候,执行了一些额外的任务,取消当前的操作. 我想应该是有很多图片加载的操作,当程序退到后台时,这些操作尚未开始,SD就将其取消了. 代码如下:

        Class UIApplicationClass = NSClassFromString(@"UIApplication");
        BOOL hasApplication = UIApplicationClass && [UIApplicationClass respondsToSelector:@selector(sharedApplication)];
        if (hasApplication && [self shouldContinueWhenAppEntersBackground]) { //当app进入后台时,仍继续加载.
            __weak __typeof__ (self) wself = self;
            UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)];
            self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{
                __strong __typeof (wself) sself = wself;

                if (sself) {
                    //取消队列里面的下载操作.
                    [sself cancel];
                    //下面两步是必须的
                    [app endBackgroundTask:sself.backgroundTaskId];
                    sself.backgroundTaskId = UIBackgroundTaskInvalid;
                }
            }];
        }

具体用法可以看下文档,解释的很清楚.当调用了beginBackgroundTaskWithExpirationHandler:这个方法后,一定要调用endBackgroundTask:这个方法. 如果有多个需要在后台执行的方法,那么上述的两个方法要一一对应. 不仅仅这里用到了后台执行任务,通过看源码,我们可以了解到后台执行任务的用法,以及用途.

##304 在NSURLSessionDataDelegate的代理方法中,作者有对服务器的返回值进行了判断.比如400以上的状态码意味着请求图片失败.

400系列是请求错误, 500系列的是服务器错误.

还有一个就是304,这个304是指内容没有改变,那么服务器返回这个状态码. 如果服务器返回的是304,那么直接取消当前的Operation.

##Orientation 图片的方向问题,如果做过相机拍照的话,会发现把手机横过来拍照,这样的图片才是我们眼中的的图片. 如果竖着手机拍的话,会发现图片显示时,方向是不对的.这里涉及到了照片的存储方式. 具体详情请看如何处理iOS中照片的方向,解释的很精彩.

##主要的流程 SD实现了一个便利构造方法,对外开放,并且接受一些参数,例如progressBlock,completedBlock,cancelBlock等.

start方法,也是关键方法.当一个NSOperation对象被添加到一个NSOperationQueue的时候,会执行start方法.

cancel方法,执行了一些取消操作,以及将实例变量置空等.

还有就是一堆的NSURLSessionDataDelegateNSURLSessionTaskDelegate的代理方法.代理方法中还有对接收到的data进行处理,然后得到图片.这一块我没关注.

#总结

SDWebImageDownloaderOperation是下载图片的核心功能. 我在看的时候,没有关注对图片数据的处理,更多的是理解这个类的设计. 主要的就是要根据开放文档中写的Guide,遵守一些基本的规范. 以及对一些错误的处理,和取消操作的处理.

如果有什么错误,还请不吝指出.感激不尽.