本文主要内容
一.AFNetworking
二.SDWebImageView
三.Reactive Cocoa
四.AsyncDisplayKit
一.AFNetworking
1.1、框架图
在AFNetworking这个第三方网络库中,首先由会话(即NSURLSession)部分组成;其次是网络监听模块,用来监听网络的变化,并且进行相关的逻辑处理;第三部分为网络安全模块。同时AFNetworking对请求和响应进行了序列化的封装,在此之上又有关于UIKit集成模块,如UIKit原生控件分类的添加,以上所有构成了AFNetworking整体框架。
1.2、主要类关系图
在AFNetworking库中核心类为AFURLSessionManager,核心类内部又包含会话NSURLSession、AFSecurityPolicy(进行网络证书的校验、公钥的校验等,保证网络安全)、AFNetworkingReachabilityManager(对网络连接进行监听)等内容。核心类有一个子类AFHTTPSessionManager,该子类包含AFURLRequestSer ialization(用来负责根据传进来的参数组装/拼接最终的结果,即NSMutableU RLRequest)和AFURLResponseSerialization(负责响应序列化,对网络请求返回结果进行解析,有对应解析方法,如json、image等的)。
总结来说,AFURLSessionManager主要工作:
- 创建和管理NSURLSession、NSURLSessionTask(对应一个网络请求);
- 实现NSURLSessionDelegate等协议的代理方法;
- 引入AFSecurityPolicy保证请求安全;
- 引入AFNetworkingReachabilityManager监控网络状态。
例:发送一个GET方式的HTTP请求关键代码
// "AFHTTPSessionManager.m"
#pragma mark - GET
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
progress:(nullable void (^)(NSProgress * _Nonnull))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))failure {
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
headers:headers
uploadProgress:downloadProgress
success:success
failure:failure];
[dataTask resume];
return dataTask;
}
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure {
NSError *serializationError = nil;
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
for (NSString *headerField in headers.keyEnumerator) {
[request setValue:headers[headerField] forHTTPHeaderField:headerField];
}
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
return dataTask;
}
复制代码
// "AFURLRequestSerialization.m"
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error {
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
for (NSString *keyPath in self.mutableObservedChangedKeyPaths) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
return mutableRequest;
}
复制代码
// "AFURLSessionManager.m"
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
复制代码
二.SDWebImage
2.1、架构简图
SDWebImage框架中主要封装了一些UIKit的分类方法。其中SDWebImageManage r为其核心工作类,SDImageCache负责处理图片的缓存(包括磁盘缓存和内存缓存管理),SDWebImageDownloader负责具体图片的下载器。
2.2、加载图片的流程
详细流程描述:
1、加载图片的入口方法为
setImageWithURL:placeholderImage:option s:,先显示默认占位图placeholderImage;
2、然后SDWebImageManager根据URL开始处理图片,调用方法downlo adWithURL:delegate:options:userInfo:,通过SDImageCache从缓存查找图片是否已经下载queryDiskCacheForKey:delegate:userInfo:; 3、先从内存图片缓存查找是否有图片,如果内存汇总已经有图片缓存,SDImageCacheDelegate回调imageCache:didFindImage:forKey:userI nfo:到SDWebImageManager,SDWebImageManagerDelegate回调webI mageManager:didiFinishWithImage:到UIImageView+WebCache等前端展示图片;
4、如果内存中没有,生成NSInvocationOperation添加到队列,开始从磁盘查找图片是否已经缓存;
5、根据URLKey在磁盘缓存目录下尝试读取图片文件,这一步是在NSOperation进行的操作,所以回主线程进行结果回调notifyDelegate:。如果从磁盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存),SDImageCacheDelegate回调imageCache:didFindImage:forKey:userInfo:,进而回调展示图片; 6、如果从磁盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调imageCache:didNotFindImageForKey:userIn fo:;
7、共享或重新生成一个下载器SDWebImageDownloader开始下载图片,图片下载由NSURLConnection来做,实现相关delegate来判断图片下载中、下载完成和下载失败。connection:didReceiveData:中利用ImageIO做了按图片下载进度加载效果。connectionDidFinishLoading:数据下载完成后交给SDWebImageDecoder做图片解码处理。图片解码处理在一个NSOperationQueue完成,不会拖慢主线程UI,如有需要对下载的图片进行二次处理,最好也在这里完成,效率会高很多;
8、在主线程notifyDelegateOnMainThreadWithInfo:宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo:回调给SDWebIma geDownloader,imageDownloader:didFinishWithImage:回调给SDW ebImageManager告知图片下载完成,通知所有的downloadDelegates下载完成,回调给需要的地方展示图片;
9、将图片保存到SDImageCache中,内存缓存和磁盘缓存同时保存,写文件到磁盘也单独在NSInvocationOperation中完成,避免拖慢主线程;
SDImageCache在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片;SDWebImagePrefetcher可以预先下载图片,方便后续使用。
三.ReactiveCocoa
编程思想介绍
函数式编程(Functional Programming):
1、把操作尽量写成一系列嵌套的函数或者方法调用;
2、每个方法必须有返回值(本身对象),把函数或者Block当作参数,block参数(需要操作的值)block返回值(操作结果),即每一步都需要有结果。响应式编程(Reactive Programming): 1、不需要考虑调用顺序,只需要知道考虑结果,即一个改变就会使结果改; 2、典型例子(AutoLayout):aView上添加子view,当aView约束发生变化时,子view也会随之改变。
如何导入Reactive Cocoa框架
通常使用CocoaPods导入。
- ReactiveObjC -- 对应的是RAC的OC版本
- Reactive Cocoa -- 对应的是RAC的swift版本
3.1、什么是函数响应式编程
ReactiveCocoa是一个函数响应式编程框架,可以订阅一个信号就是函数响应式编程的核心概念。
3.2、信号
- 该框架中的核心类为
RACSignal。
-
通过父类
RACStream的组成结构,了解信号 -
信号代表一连串的状态
如下图,信号处于1状态,由于数据的变化,会从1状态切换到2状态,数据再变化会导致信号继续变化,最后是end。在状态改变时,对应的订阅者RACSubscriber就会收到通知执行响应的指令。 复制代码
RACSignal包含子类RACReturnSignal、RACDynamicSignal。以下通过看源码理解信号
RACDynamicSignal
// RACReturnSignal.m
+ (RACSignal *)return:(id)value {
......
RACReturnSignal *signal = [[self alloc] init];
signal->_value = value;
......
}
复制代码
RACDynamicSignal
// RACSignal.m
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal: didSubscribe];
}
// RACDynamicSignal.m
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}
复制代码
3.3、订阅
- 订阅者
RACSubscriber
3.3.1 、订阅的逻辑流程
首先开始订阅一个信号RACSignal,然后调用RACSignal的-subscriveNext:方法,该方法中会产生一个RACSubscriber类,调用RACSignal的-sendNext:方法,在-sendNext:方法内部又会调用-sendCompleted方法,结束订阅流程。
3.3.2、RACSubscriber订阅的内部原理
当产生一个RACSubscriber类时,会在其内部持有一个成员变量,即didSubscribe(Block),调用RACSubscriber时会调用此Block,如下:
{
[RACSignal return:@3];
[RACSignal subScribedNext:^(id x){
NSLog(@"%@",x);
}];
}
复制代码
四.AsyncDisplayKit
4.1、主要处理问题
- 解决布局的耗时运算
- 解决渲染问题
- 处理UIKit对象 将可以移到子线程中处理的问题移到子线程处理。
4.2、基本原理
- 1、针对ASNode的修改和提交,会对其进行封装并提交到一个全局容器当中;
- 2、ASDK也在Runloop中注册一个Observer;
- 3、当Runloop进入休眠前,ASDK执行该loop内提交的所有任务。