由于公司的网络库使用的是AFNetworking旧版本,所以最近研究了这版的AFNetworking的源码,下面我们就简单介绍一下AFNetworking的核心类:
AFNetworkActivityIndicatorManager : NSObject,用来根据当前是否有网络请求,来设置状态栏菊花是否显示。
AFHTTPClient : NSObject,作为请求的入口,封装了请求的get、post等方法,以及对http的header操作的方法
AFURLConnectionOperation : NSOperation ,继承自NSOperation,是所有网络请求operation的基类,实现了NSURLConnection的代理方法,管理connection的start方法以及响应数据的处理
AFHTTPRequestOperation : AFURLConnectionOperation,对AFURLConnectionOperation进行封装,request请求使用的协议为HTTP和HTTPS,它对决定request请求是否成功的状态码和内容类型进行了封装,并且可以设置请求成功或者失败的回调;其他具体的requestOperation可以直接继承AFHTTPRequestOperation,实现简单的父类方法即可
//一个布尔值,它对应于响应的状态码是否在指定的一组可接受的状态码之内。 如果acceptableStatusCodes`为nil,则返回YES。
@property (readonly) BOOL hasAcceptableStatusCode;
//一个布尔值,它对应于响应的MIME类型是否在指定的一组可接受的内容类型之中。 如果acceptableContentTypes为nil,则返回YES。
@property (readonly) BOOL hasAcceptableContentType;
+ (NSIndexSet *)acceptableStatusCodes;
+ (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes;
+ (NSSet *)acceptableContentTypes;
+ (void)addAcceptableContentTypes:(NSSet *)contentTypes;
//决定一个请求能否被处理
+ (BOOL)canProcessRequest:(NSURLRequest *)urlRequest;
//设置请求成功/失败的回调
- (void)setCompletionBlockWithSuccess:(void (^)(WBTDAFHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(WBTDAFHTTPRequestOperation *operation, NSError *error))failure;
- AFDownloadRequestOperation:AFHTTPRequestOperation,创建一个下载的operation,并且返回下载进度
- AFImageRequestOperation : AFHTTPRequestOperation,封装了下载图片的请求operation,之后operation执行后,请求成功返回图片,请求失败返回错误原因;缺点没有使用缓存机制。
@property (readonly, nonatomic, retain) UIImage *responseImage;
+ (AFImageRequestOperation *)imageRequestOperationWithRequest: success:
+ (AFImageRequestOperation *)imageRequestOperationWithRequest:imageProcessingBlock:success:failure
- AFJSONRequestOperation : AFHTTPRequestOperation,用于下载和处理返回数据格式是json的数据
//根据响应数据构造的JSON对象。 如果解析时发生错误,则将返回nil,并且将error属性设置为错误。
@property (readonly, nonatomic, retain) id responseJSON;
//创建返回AFJSONRequestOperation对象的请求,并且可以设置成功or失败的回调
+ (AFJSONRequestOperation *)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure;
- AFPropertyListRequestOperation : AFHTTPRequestOperation,用于下载和处理返回数据格式是property list的数据
@property (readonly, nonatomic, retain) id responsePropertyList;
@property (nonatomic, assign) NSPropertyListReadOptions propertyListReadOptions;
+(AFPropertyListRequestOperation *)propertyListRequestOperationWithRequest:success:failure:
- AFXMLRequestOperation : AFHTTPRequestOperation,用于下载和处理返回数据格式是xml的数据
//根据响应数据构造的“ NSXMLParser”对象。
@property (readonly, nonatomic, retain) NSXMLParser *responseXMLParser;
//根据响应数据构造的“ NSXMLDocument”对象。 如果解析时发生错误,则将返回nil,并且将error属性设置为错误。
@property (readonly, nonatomic, retain) NSXMLParser *responseXMLDocument;
@property (readonly, nonatomic, retain) id responseJSON;
//创建返回AFXMLRequestOperation对象的请求,并且可以设置成功or失败的回调
+ (AFXMLRequestOperation *)XMLParserRequestOperationWithRequest:success:failure:
+ (AFXMLRequestOperation *)XMLDocumentRequestOperationWithRequest:success:failure:
主要的逻辑在AFNetworking和AFURLConnectionOperation类中,下面我们详细介绍一下 AFURLConnectionOperation和AFHTTPClient
(1)AFURLConnectionOperation是对NSURLConnection的封装,实现网络请求的建立,并且实现NSURLConnection的代理方法获取请求的response或者请求错误等
(2)AFHTTPClient:
AFHTTPClient :封装了网络状态监听、请求编码、请求地址、请求参数以及对请求队列的管理。
(1)AFHTTPClient文件给出的使用建议包含:
-
可以实现获取期望的解析完成的resopnse数据。
AFHTTPClient的实例可以通过注册用于自动解析的HTTP操作类来指定期望的类型和应该处理的请求类型,例如AFJSONRequestOperation来获取解析为json数据的response、使用AFImageRequestOperation获取图片,然后在“ enqueueHTTPRequestOperationWithRequest:success:failure”中相应地构造一个请求操作。
-
子类化
使用的时候,为app和服务器交互的每个网络请求创建一个AFHTTPClient子类,在子类中返回一个http client的共享单例,便于在整个应用程序中保留身份验证凭据和相关网络请求配置。
-
方法的继承
-
重写requestWithMethod:path:parameters方法,可以改变所有AFHTTPClient子类的url请求的构建;
-
重写HTTPRequestOperationWithRequest:success:failure方法,可以改变所有AFHTTPClient子类的request请求
-
-
默认的header
“ AFHTTPClient”设置关于HTTP header设置了一些默认值:
-
Accept-Encoding:gzip
-Accept-Language:(逗号分隔的首选语言),en-us; q = 0.8
-User-Agent :(生成的用户代理)
在使用时,可以覆盖这些HTTP header或使用
setDefaultHeader:value:
定义新的请求header。 -
使用相对路径构造URL
-requestWithMethod:path:parameters:
和-multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:
都使用NSURL 的+ URLWithString:relativeToURL:从-baseURL的请求路径中构造URL。 -
NSCoding / NSCopying一致性
AFHTTPClient遵守NSCoding和NSCopying协议,允许将operations归档到磁盘、复制到内存中,但是注意下面几项:
-HTTP客户端的archives和copies使用的是空操作队列进行初始化。
-NSCoding无法序列化/反序列化block属性,因此HTTP客户端的archives不包含block。
下面我们来研究一下AFHTTPClient中网路状态的监控逻辑,AFNetworking中的网络检测主要逻辑如下:
- (void)startMonitoringNetworkReachability {
[self stopMonitoringNetworkReachability];
if (!self.baseURL) {
return;
}
//1、获取该域名的网络连接的引用
self.networkReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [[self.baseURL host] UTF8String]);
WBTDAFNetworkReachabilityStatusBlock callback = ^(WBTDAFNetworkReachabilityStatus status){
self.networkReachabilityStatus = status;
if (self.networkReachabilityStatusBlock) {
self.networkReachabilityStatusBlock(status);
}
};
//2、创建网络引用的context容器
SCNetworkReachabilityContext context = {0, callback, WBTDAFNetworkReachabilityRetainCallback, WBTDAFNetworkReachabilityReleaseCallback, NULL};
//3、网络变化时将client分配给一个target
SCNetworkReachabilitySetCallback(self.networkReachability, WBTDAFNetworkReachabilityCallback, &context);
//4、将target安排到对应的runloop和model中
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), (CFStringRef)NSRunLoopCommonModes);
/* Network reachability monitoring does not establish a baseline for IP addresses as it does for hostnames, so if the base URL host is an IP address, the initial reachability callback is manually triggered.
*/
if (WBTDAFURLHostIsIPAddress(self.baseURL)) {
//5、获取当前网络连接的标志
SCNetworkReachabilityFlags flags;
SCNetworkReachabilityGetFlags(self.networkReachability, &flags);
//6、网络发生变化后更新状态并且执行相应的回调
dispatch_async(dispatch_get_main_queue(), ^{
WBTDAFNetworkReachabilityStatus status = WBTDAFNetworkReachabilityStatusForFlags(flags);
callback(status);
});
}
}
AFNetworking中网络状态的监听实现大概流程如下:
使用SCNetworkReachabilityCreateWithName()初始化函数,获取一个SCNetReachabilityRef的引用,然后使用SCNetworkReachabilityCallBack定义是一个网络监听的回调blcok,网络状态发生变化之后执行,然后初始化一个SCNetworkingReachabilityContext上下文信息,初始化SCNetworkingReachabilitySetCallback()函数传入上述 ref、callback、context 3个参数,设置Ref引用在网络变化时执行的回调blcok,通过调用SCNetworkReachabilityScheduleWithRunLoop()函数并传入Ref,在 Current Runloop 中开始或取消监听网络连接状态变化;最后调用SCNetworkReachabilityGetFlags()函数并传入Ref,可获得当前网络连接状态的 flags 枚举值,设置网络状态并且发送网络变化的通知。
注意:当 DNS 服务器无法连接或在弱网环境下,SCNetworkingReabilityGetFlags()函数将会很耗时,所以苹果建议在子线程里异步调用此函数,然后根据不同的 SCNetworkReachabilityFlags枚举值,判断当前网络连接状态和连接类型。
网络监听使用的API介绍
1、SCNetworkReachabilityRef SCNetworkReachabilityCreateWithName(CFAllocatorRef allocator, const char *nodename);根据传入的网址获得网络连接的引用,其中SCNetworkReachabilityRef表示创建的网络连接的引用,SCNetworkReachabilityCreateWithName函数参数介绍如下
- CFAllocatorRef allocator, //可以为NULL或kCFAllocatorDefault
- const char *nodename //比如为"www.baidu.com",此参数为域名
2、SCNetworkReachabilityContext 包含了用户数据和SCNetworkReachability的callback
typedef struct
{
CFIndex version;
void * __nullable info;
const void * __nonnull (* __nullable retain)(const void *info);
void (* __nullable release)(const void *info);
CFStringRef __nonnull (* __nullable copyDescription)(const void *info);
} SCNetworkReachabilityContext;
4、SCNetworkReachabilityScheduleWithRunLoop
SCNetworkReachabilityScheduleWithRunLoop (
SCNetworkReachabilityRef target,
CFRunLoopRef runLoop,
CFStringRef runLoopMode
)
5、SCNetworkReachabilityFlags枚举类型,定义正常测试的网络的可达性的类型,常用的类型有以下几种
- kSCNetworkReachabilityFlagsReachable:能够连接网络
- kSCNetworkReachabilityFlagsConnectionRequired:能够连接网络,但是首先得建立连接过程
- kSCNetworkReachabilityFlagsIsWWAN:判断是否通过蜂窝网覆盖的连接,比如EDGE,GPRS或者目前的3G.主要是区别通过WiFi的连接。
(1)AFNetworking目前检测的网络类型
-
AFNetworkReachabilityStatusUnknown = -1,
-
AFNetworkReachabilityStatusNotReachable = 0,//网络不可用
-
AFNetworkReachabilityStatusReachableViaWWAN = 1,//移动网络连接
-
AFNetworkReachabilityStatusReachableViaWiFi = 2,//wifi连接
(2)如果要获取当前正在检测的网络可达性类型,可以通过下面函数来获取相应的类型
SCNetworkReachabilityGetFlags (
SCNetworkReachabilityRef target, //正在检测的网络连接的引用
SCNetworkReachabilityFlags *flags //用来保存获得的状态
);
知识点
OC中与网络设置、检测相关的API由SystemConfiguration静态库提供,AFNetworking、Reachability都是借助SystemConfiguration框架来完成的。