AFNetworking源码分析(一)

来源:互联网 发布:aws ubuntu安装锐速 编辑:程序博客网 时间:2024/05/22 05:06

出于提高自己对ios技术的考虑,决定研究一下优秀的第三方开源框架的源码,以防自己的辣鸡记性把看过的东西忘得光光的,在这里做一下记录吧。毕竟也不是什么大神,所以都是一些自己的理解,观者如果有不同意见,希望轻喷!


对于AFNetWorking的框架已经进入了3.0在这里就不再分析前面版本的框架了。AFN主要用于对网络请求的封装,在后面的文章里还会描述一种笔者抄袭腾讯云demo的二次封装方法,笔者认为还是值得借鉴的。


首先我们先从AFNetworking.h文件入手


#import <Foundation/Foundation.h>#import <Availability.h>#import <TargetConditionals.h>#ifndef _AFNETWORKING_    #define _AFNETWORKING_    #import "AFURLRequestSerialization.h"    #import "AFURLResponseSerialization.h"    #import "AFSecurityPolicy.h"#if !TARGET_OS_WATCH    #import "AFNetworkReachabilityManager.h"#endif    #import "AFURLSessionManager.h"    #import "AFHTTPSessionManager.h"#endif /* _AFNETWORKING_ */

这个文件很简单,只是引入了一些其他的文件,其中AFNetworkReachabilityManager,h文件是不支持watchOS的。前面的两个宏_AFNETWORKING_的判断是防止文件的多次引用。Aviailability.h是用于判断系统版本的而TargetConditionals.h中是一些用来判断当前编译器的类型的宏


这些文件中AFURLSessionManager.h(下文将此类成为URLManager)和AFHTTPSessionManager.h(下文将此类成为HTTPManager)最为重要HTTPManager类是URLManager类的子类,因此URLManager类是最核心的类,但是在介绍这两个类之前,我们需要先了解一下其他三个文件,AFURLRequestSerialization.h及一下两个。


首先是AFURLRequestSerialization.h,中所周知一个网络数据报包括请求跟相应,这个文件的主要功能,就是配置一个网络数据报的请求的相关项。下面我们将会逐个分析该文件中AFHTTPRequestSerializer类的属性和方法。

1.stringencoding:这是设置一个请求的编码格式,默认编码格式为UTF8

/** The string encoding used to serialize parameters. `NSUTF8StringEncoding` by default. */@property (nonatomic, assign) NSStringEncoding stringEncoding;


2.allowsCellularAccess:这个属性设置是是否允许使用蜂窝数据也就是使用流量请求,默认为YES

/** Whether created requests can use the device’s cellular radio (if present). `YES` by default. @see NSMutableURLRequest -setAllowsCellularAccess: */@property (nonatomic, assign) BOOL allowsCellularAccess;

3.cachePolicy:这个属性是设置缓存策略,缓存策略有6中,这篇文章中有每种缓存策略的详细介绍:点击打开链接

/** The cache policy of created requests. `NSURLRequestUseProtocolCachePolicy` by default. @see NSMutableURLRequest -setCachePolicy: */@property (nonatomic, assign) NSURLRequestCachePolicy cachePolicy;

4.HTTPShouldHandleCookies:这个属性设置是否要在请求时加上cookie,默认为YES,请求会将cookie的值自动加载请求头中

/** Whether created requests should use the default cookie handling. `YES` by default. @see NSMutableURLRequest -setHTTPShouldHandleCookies: */@property (nonatomic, assign) BOOL HTTPShouldHandleCookies;

5.HTTPShouldUsePipelining:这个属性用于在请求后是否要等待回复后再请求下一个,默认为NO,即需要等待回复后再进行下一个请求

/** Whether created requests can continue transmitting data before receiving a response from an earlier transmission. `NO` by default @see NSMutableURLRequest -setHTTPShouldUsePipelining: */@property (nonatomic, assign) BOOL HTTPShouldUsePipelining;

6.networkServiceType:这个属性是设置网络服务类型,其中包括后台文件下载、音频、视频等,这个属性具体的用途是传递设置给官方的NSURLRequest,根据查询资料,笔者认为这个属性是用于对下载大文件或者一些特殊的网络请求系统会进行一些性能优化等等操作。

/** The network service type for created requests. `NSURLNetworkServiceTypeDefault` by default. @see NSMutableURLRequest -setNetworkServiceType: */@property (nonatomic, assign) NSURLRequestNetworkServiceType networkServiceType;

7.timeoutInterval:这个属性很好理解,就是设置请求的超时时间默认为一分钟

/** The timeout interval, in seconds, for created requests. The default timeout interval is 60 seconds. @see NSMutableURLRequest -setTimeoutInterval: */@property (nonatomic, assign) NSTimeInterval timeoutInterval;

8.HTTPRequestHeaders:这个字典是一个只读属性,可以读取这个请求的所有请求头,当然这因为是只读属性,因此不会牵扯到需要copy来复制出来一份内容保存,直接保存原来的私有变量的内容地址即可,因此用了strong类型的指针

/** Default HTTP header field values to be applied to serialized requests. By default, these include the following: - `Accept-Language` with the contents of `NSLocale +preferredLanguages` - `User-Agent` with the contents of various bundle identifiers and OS designations @discussion To add or remove default request headers, use `setValue:forHTTPHeaderField:`. */@property (readonly, nonatomic, strong) NSDictionary <NSString *, NSString *> *HTTPRequestHeaders;


9.HTTPMethodsEncodingParametersInURI:这个属性是一个NSSet,里面储存的是请求可支持哪些方法,默认是支持GET、HEAD和DELETE。这个属性一般在发出POST请求的时候有用到,如果没有在这里加入POST,参数就会拼到body里面,导致服务端无法找到参数,因此就需要将POST加入到这个Set里面去。

/** HTTP methods for which serialized requests will encode parameters as a query string. `GET`, `HEAD`, and `DELETE` by default. */@property (nonatomic, strong) NSSet <NSString *> *HTTPMethodsEncodingParametersInURI;




以上就是请求类的所有属性,下面我们来介绍一下该类所用到的方法:


1.类方法,默认创建一个请求的配置,所有配置值都是框架默认的。

/** Creates and returns a serializer with default configuration. */+ (instancetype)serializer;


2.用于设置请求头的方法,可以设置请求的请求头例如Accept、Content-Type等,请求头大全


/** Sets the value for the HTTP headers set in request objects made by the HTTP client. If `nil`, removes the existing value for that header. @param field The HTTP header to set a default value for @param value The value set as default for the specified header, or `nil` */- (void)setValue:(nullable NSString *)valueforHTTPHeaderField:(NSString *)field;


3.这个方法是用来根据请求头的key来查询请求头的value

/** Returns the value for the HTTP headers set in the request serializer. @param field The HTTP header to retrieve the default value for @return The value set as default for the specified header, or `nil` */- (nullable NSString *)valueForHTTPHeaderField:(NSString *)field;


4.这个方法是用来设置请求头中的一个特殊的请求头,类似于一个用户的鉴权,会根据用户填写的信息,通过base64的编码方式转换为一串编码,设置到请求头Authorization中,这个可以通过上面的setValue:forHTTPHeaderField来实现


/** Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a basic authentication value with Base64-encoded username and password. This overwrites any existing value for this header. @param username The HTTP basic auth username @param password The HTTP basic auth password */- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username                                       password:(NSString *)password;


5.这个方法用于清理请求头中的鉴权。


/** Clears any existing value for the "Authorization" HTTP header. */- (void)clearAuthorizationHeader;

6.这个方法和下面的block方法适用于query string的序列化格式的,具体的作用还没有太理解,但是好像很少用到这两个方法,个人认为应该是在GET请求时,设置字符串凭借到url后面的格式,第一个暂时只有个默认格式就是常见的?&的格式,第二个是block如果对请求参数拼接有特殊需求,可以传递一个block,返回值是拼接好的query string

/** Set the method of query string serialization according to one of the pre-defined styles. @param style The serialization style. @see AFHTTPRequestQueryStringSerializationStyle */- (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style;/** Set the a custom method of query string serialization according to the specified block. @param block A block that defines a process of encoding parameters into a query string. This block returns the query string and takes three arguments: the request, the parameters to encode, and the error that occurred when attempting to encode parameters for the given request. */- (void)setQueryStringSerializationWithBlock:(nullable NSString * (^)(NSURLRequest *request, id parameters, NSError * __autoreleasing *error))block;

7.接下来的这个方法是该类中最重要的一个方法,用于拼接一个NSURLRequest对象,拼接好的对象可以用于发送请求。具体这个方法的详细实现会在另一篇文章中描述

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method                                 URLString:(NSString *)URLString                                parameters:(nullable id)parameters                                     error:(NSError * _Nullable __autoreleasing *)error;


8.这个方法是在上一个方法的基础上用于处理POST请求的,如果是GET请求和HEAD请求,会直接报错,该方法,会根据用户传入的block获取一个遵循AFMultipartFormData协议的对象,在当前方法中是AFStreamingMultipartFormData对象。详细实现也会在上一个方法的文章中描述。


- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method                                              URLString:(NSString *)URLString                                             parameters:(nullable NSDictionary <NSString *, id> *)parameters                              constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block                                                  error:(NSError * _Nullable __autoreleasing *)error;

9.这个方法是一个额外的方法,用于把一个request的body保存到一个文件中,笔者猜测应该是用于在一个长时间很重要的请求前,缓存下俩请求内容,如果请求失败,那么可以直接从文件中获取到请求内容重新请求

- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request                             writingStreamContentsToFile:(NSURL *)fileURL                                       completionHandler:(nullable void (^)(NSError * _Nullable error))handler;


到这里AFHTTPRequestSerializer类的所有属性和方法都分析完了。下面就是一个AFMultipartFormData的协议,在使用POST请求的时候传递参数需要返回遵循该协议的对象。该协议内是一些根据不同格式拼接参数的方法。



@protocol AFMultipartFormData/** Appends the HTTP header `Content-Disposition: file; filename=#{generated filename}; name=#{name}"` and `Content-Type: #{generated mimeType}`, followed by the encoded file data and the multipart form boundary. The filename and MIME type for this data in the form will be automatically generated, using the last path component of the `fileURL` and system associated MIME type for the `fileURL` extension, respectively. @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`. @param name The name to be associated with the specified data. This parameter must not be `nil`. @param error If an error occurs, upon return contains an `NSError` object that describes the problem. @return `YES` if the file data was successfully appended, otherwise `NO`. */- (BOOL)appendPartWithFileURL:(NSURL *)fileURL                         name:(NSString *)name                        error:(NSError * _Nullable __autoreleasing *)error;/** Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`. @param name The name to be associated with the specified data. This parameter must not be `nil`. @param fileName The file name to be used in the `Content-Disposition` header. This parameter must not be `nil`. @param mimeType The declared MIME type of the file data. This parameter must not be `nil`. @param error If an error occurs, upon return contains an `NSError` object that describes the problem. @return `YES` if the file data was successfully appended otherwise `NO`. */- (BOOL)appendPartWithFileURL:(NSURL *)fileURL                         name:(NSString *)name                     fileName:(NSString *)fileName                     mimeType:(NSString *)mimeType                        error:(NSError * _Nullable __autoreleasing *)error;/** Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the data from the input stream and the multipart form boundary. @param inputStream The input stream to be appended to the form data @param name The name to be associated with the specified input stream. This parameter must not be `nil`. @param fileName The filename to be associated with the specified input stream. This parameter must not be `nil`. @param length The length of the specified input stream in bytes. @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. */- (void)appendPartWithInputStream:(nullable NSInputStream *)inputStream                             name:(NSString *)name                         fileName:(NSString *)fileName                           length:(int64_t)length                         mimeType:(NSString *)mimeType;/** Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. @param data The data to be encoded and appended to the form data. @param name The name to be associated with the specified data. This parameter must not be `nil`. @param fileName The filename to be associated with the specified data. This parameter must not be `nil`. @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. */- (void)appendPartWithFileData:(NSData *)data                          name:(NSString *)name                      fileName:(NSString *)fileName                      mimeType:(NSString *)mimeType;/** Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary. @param data The data to be encoded and appended to the form data. @param name The name to be associated with the specified data. This parameter must not be `nil`. */- (void)appendPartWithFormData:(NSData *)data                          name:(NSString *)name;/** Appends HTTP headers, followed by the encoded data and the multipart form boundary. @param headers The HTTP headers to be appended to the form data. @param body The data to be encoded and appended to the form data. This parameter must not be `nil`. */- (void)appendPartWithHeaders:(nullable NSDictionary <NSString *, NSString *> *)headers                         body:(NSData *)body;/** Throttles request bandwidth by limiting the packet size and adding a delay for each chunk read from the upload stream. When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted". Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize` and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth. Unfortunately, there is no definite way to distinguish between a 3G, EDGE, or LTE connection over `NSURLConnection`. As such, it is not recommended that you throttle bandwidth based solely on network reachability. Instead, you should consider checking for the "request body stream exhausted" in a failure block, and then retrying the request with throttled bandwidth. @param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 16kb. @param delay Duration of delay each time a packet is read. By default, no delay is set. */- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes                                  delay:(NSTimeInterval)delay;@end



接下来是一个AFHTTPRequestSerializer的子类叫AFJSONRequestSerializer的类,主要的改变是重写了创建request的方法,其中的主要区别只是将ContentType的类型改为默认application/json。一般请求接口时使用的是这类请求格式。

PropertyList


接下来是另一个AFHTTPRequestSerializer的子类叫AFPropertyListRequestSerializer的类,主要的改变是重写了创建request的方法,其中的主要区别只是将ContentType的类型改为默认application/x-plist

具体要选哪种请求的格式需要跟你的后台对接,看后台可以识别什么样的数据。


以上就是AFN中的AFURLRequestSerialization类的源码分析,这是最主要的一个类,后面我们会继续进行AFN的其他源码分析。

原创粉丝点击