該文章閱讀的AFNetworking的版本爲3.2.0。web
這個分類提供了對請求週期進行控制的方法,包括進度監控、成功和失敗的回調。bash
/**
網絡會話管理者對象
*/
@property (nonatomic, strong) AFHTTPSessionManager *sessionManager;
複製代碼
/**
異步加載指定請求
*/
- (void)loadRequest:(NSURLRequest *)request
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(nullable NSString * (^)(NSHTTPURLResponse *response, NSString *HTML))success
failure:(nullable void (^)(NSError *error))failure;
/**
以指定MIME類型和指定文本編碼格式異步加載指定請求
*/
- (void)loadRequest:(NSURLRequest *)request
MIMEType:(nullable NSString *)MIMEType
textEncodingName:(nullable NSString *)textEncodingName
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(nullable NSData * (^)(NSHTTPURLResponse *response, NSData *data))success
failure:(nullable void (^)(NSError *error))failure;
複製代碼
/**
保存任務對象
*/
@property (readwrite, nonatomic, strong, setter = af_setURLSessionTask:) NSURLSessionDataTask *af_URLSessionTask;
複製代碼
這兩個方法就是經過Runtime的關聯對象爲分類添加屬性保存任務對象網絡
- (NSURLSessionDataTask *)af_URLSessionTask {
return (NSURLSessionDataTask *)objc_getAssociatedObject(self, @selector(af_URLSessionTask));
}
- (void)af_setURLSessionTask:(NSURLSessionDataTask *)af_URLSessionTask {
objc_setAssociatedObject(self, @selector(af_URLSessionTask), af_URLSessionTask, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
複製代碼
下面的這四個方法一樣是經過關聯對象爲分類添加屬,分別是保存網絡會話管理者對象和響應序列化對象session
- (AFHTTPSessionManager *)sessionManager {
static AFHTTPSessionManager *_af_defaultHTTPSessionManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_af_defaultHTTPSessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
_af_defaultHTTPSessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
_af_defaultHTTPSessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
});
return objc_getAssociatedObject(self, @selector(sessionManager)) ?: _af_defaultHTTPSessionManager;
}
- (void)setSessionManager:(AFHTTPSessionManager *)sessionManager {
objc_setAssociatedObject(self, @selector(sessionManager), sessionManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (AFHTTPResponseSerializer <AFURLResponseSerialization> *)responseSerializer {
static AFHTTPResponseSerializer <AFURLResponseSerialization> *_af_defaultResponseSerializer = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_af_defaultResponseSerializer = [AFHTTPResponseSerializer serializer];
});
return objc_getAssociatedObject(self, @selector(responseSerializer)) ?: _af_defaultResponseSerializer;
}
- (void)setResponseSerializer:(AFHTTPResponseSerializer<AFURLResponseSerialization> *)responseSerializer {
objc_setAssociatedObject(self, @selector(responseSerializer), responseSerializer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
複製代碼
- (void)loadRequest:(NSURLRequest *)request
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(NSString * (^)(NSHTTPURLResponse *response, NSString *HTML))success
failure:(void (^)(NSError *error))failure
{
// 調用下面的方法
[self loadRequest:request MIMEType:nil textEncodingName:nil progress:progress success:^NSData *(NSHTTPURLResponse *response, NSData *data) {
// 設置字符編碼方式爲UTF8
NSStringEncoding stringEncoding = NSUTF8StringEncoding;
// 若是響應對象有文本編碼方式,就將字符編碼方式設置爲響應的文本編碼方式
if (response.textEncodingName) {
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
if (encoding != kCFStringEncodingInvalidId) {
stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding);
}
}
// 將返回的數據進行編碼
NSString *string = [[NSString alloc] initWithData:data encoding:stringEncoding];
// 若是設置了成功回調就調用block傳遞數據
if (success) {
string = success(response, string);
}
// 將字符串編碼成二進制數據後返回
return [string dataUsingEncoding:stringEncoding];
} failure:failure];
}
- (void)loadRequest:(NSURLRequest *)request
MIMEType:(NSString *)MIMEType
textEncodingName:(NSString *)textEncodingName
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(NSData * (^)(NSHTTPURLResponse *response, NSData *data))success
failure:(void (^)(NSError *error))failure
{
// 在debug模式下缺乏參數就crash
NSParameterAssert(request);
// 若是當前已經有任務正在進行或者已經暫停,就取消掉這個任務,並將保存它的屬性置空
if (self.af_URLSessionTask.state == NSURLSessionTaskStateRunning || self.af_URLSessionTask.state == NSURLSessionTaskStateSuspended) {
[self.af_URLSessionTask cancel];
}
self.af_URLSessionTask = nil;
// 生成任務
__weak __typeof(self)weakSelf = self;
__block NSURLSessionDataTask *dataTask;
dataTask = [self.sessionManager
dataTaskWithRequest:request
uploadProgress:nil
downloadProgress:nil
completionHandler:^(NSURLResponse * _Nonnull response, id _Nonnull responseObject, NSError * _Nullable error) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
// 若是出錯就調用失敗回調block
if (error) {
if (failure) {
failure(error);
}
// 若是成功
} else {
// 先調用成功回調block
if (success) {
success((NSHTTPURLResponse *)response, responseObject);
}
// 調用UIWebView加載本地數據的方式進行加載頁面
[strongSelf loadData:responseObject MIMEType:MIMEType textEncodingName:textEncodingName baseURL:[dataTask.currentRequest URL]];
// 調用UIWebView代理中的完成加載方法
if ([strongSelf.delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
[strongSelf.delegate webViewDidFinishLoad:strongSelf];
}
}
}];
// 用屬性保存任務對象
self.af_URLSessionTask = dataTask;
// 若是設置了進度對象,就獲取到網絡會話管理者的下載進程對象
if (progress != nil) {
*progress = [self.sessionManager downloadProgressForTask:dataTask];
}
// 啓動任務
[self.af_URLSessionTask resume];
// 調用UIWebView代理中的開始加載方法
if ([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
複製代碼
看完這個分類的源碼,咱們能夠看到這個分類作的事就是,手動實現了UIWebView
加載網絡數據的過程,從而能夠監聽進度和經過block回調處理成功與失敗的結果。異步
一般,咱們會使用loadRequest:
方法加載指定頁面,而後經過UIWebViewDelegate
中的方法監聽網頁加載的開始、結束與失敗。post
而這個分類,經過AFHTTPSessionManager
類手動生成NSURLSessionDataTask
對象下載網頁的二進制數據,而後經過loadData: MIMEType: textEncodingName: baseURL:
方法加載已經下載到本地的網頁的二進制數據。在這個過程當中經過AFHTTPSessionManager
類中已經實現的方法實現進度的監控、成功和失敗的回調。ui
源碼閱讀系列:AFNetworking編碼
源碼閱讀:AFNetworking(一)——從使用入手atom
源碼閱讀:AFNetworking(二)——AFURLRequestSerializationspa
源碼閱讀:AFNetworking(三)——AFURLResponseSerialization
源碼閱讀:AFNetworking(四)——AFSecurityPolicy
源碼閱讀:AFNetworking(五)——AFNetworkReachabilityManager
源碼閱讀:AFNetworking(六)——AFURLSessionManager
源碼閱讀:AFNetworking(七)——AFHTTPSessionManager
源碼閱讀:AFNetworking(八)——AFAutoPurgingImageCache
源碼閱讀:AFNetworking(九)——AFImageDownloader
源碼閱讀:AFNetworking(十)——AFNetworkActivityIndicatorManager
源碼閱讀:AFNetworking(十一)——UIActivityIndicatorView+AFNetworking
源碼閱讀:AFNetworking(十二)——UIButton+AFNetworking
源碼閱讀:AFNetworking(十三)——UIImageView+AFNetworking
源碼閱讀:AFNetworking(十四)——UIProgressView+AFNetworking