AFNetWorking的理解
来源:互联网 发布:软件源大全 编辑:程序博客网 时间:2024/06/03 05:50
先说点题外话,从事ios开发一年,学习了苹果的好多框架,对第三方库也学习了不少,从ios6到ios8,苹果对其库的修改和完善也越来越“大而全”,当然也保留了集成度较低的api,先说说大而全api的好处,用起来很方便,不用你关心内部实现,直接在你的业务逻辑代码中使用他,但是当你根据你自己的业务逻辑进行优化的时候就没办法了,相反集成度较低的api灵活度就好的多,你可以采用自己的独特方法进行管理和使用,当然你付出的代价是自己写好多代码。有人会问,既然使用者多有自己的业务逻辑,干嘛还要使用大而全的api,其实大而全只是一个相对的概念,库的开发者会根据大多数的使用场景去继承api,那么大部分的应用场景是非常满足的,而且继承的api会提供可配置的参数,总之使用库之前根据场景选择合适的api。
关于AFNetWoring,从事iOS开发的几乎没人不知道,这个库是在NSURLConnection 和 NSURLSession的基础上进行封装的,逻辑简单清楚,设计思想很好。
1.NSURLConnection中的AF
NSRULConnection是苹果IOS2.0之后推出的用于加载URL资源的API,其使用很简单,分为同步和异步
异步
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"wwww.baidu.com"]]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"wwww.baidu.com"]]; [NSURLConnection sendAsynchronousRequest:request
<span style="white-space:pre"></span> queue:[NSOperationQueue mainQueue]
<span style="white-space:pre"></span> completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { }]同步
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"wwww.baidu.com"]]; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
解释一下,对于一个URLConnection需要一个URLRequest作为参数,然后才能load
其实同步和异步方法底层实现的本质是一样,都是告诉系统请求一个URL资源,系统会有自己私有线程去load,然后load完成后告诉调用者。而同步方法是,阻塞调用线程,然后一直等待,直到load完成,一般不会在主线程调用同步方法,这样会阻塞用户交互。异步方法是调用之后就不管了,系统加载完成后会通知调用者,通知调用者的方式有两种,一,代理方式, 系统会在connection的调用线程通知代理。二是queue方式,系统会在调用者指定的queue中通知调用者。
AFnetworing利用的是异步加载数据的方式,而且是代理的方式。首先我们来做加法讲解。
1,首先一个请求的调用必须有一个线程来执行,那么让哪个线程来做,主线程,还是其他线程,一般情况下没人用主线程,因为app中同时请求很多东西,都放在主线程里面去做那么付出的代价时主线程会各种卡顿,代理的各种交互都得让主线程去处理。那么就得用子线程。
用子线程做,创建一个NSthread,执行一个NSURLConnection,然后你得指定一个代理,代理是一个object实例,而且这个object必须拥护存储加载数据的功能,整合后就是模型1. NSThread + connection + delegateObject;
有问题吗,有,线程并发控制难以控制,那么我们就如何更改这个呢,将NStread 换成NSOperation的子类,然后用NSOperation的子类替换delegateObject,那么这样还有一个问题,NSOperation如何控制并发呢,所以我们还缺少NSOpreationQueue。NSOpreationQueue来管理NSOperation,这样并发就成功了。
整理后为模型2 NSOperation + connnetion + NSOperationQueue
模型2已经很好了,但是还有一个问题,就是 NSOperationQueue在分配一个线程去执行connection,然后load完成后,在后通知这个线程,并调用代理函数执行任务,但是一般情况下,load过程比较慢,系统中会停留一些 NSOperation执行线程,并且什么任务都不做,就是等待,所以很浪费。所以,我们这样考虑,当 NSOperationQueue分配一个线程执行NSoperation的时候我们在执行时候,让NSoperation去通知一个共有的线程去执行NSoperation的加载方法,那么NSURLConnection在加载完成后会通知调用线程,这个时候就是这个共有线程,那么其他线程就执行完成然后得以释放解脱,只有一个共有线程在忙碌,这样就不会有浪费。ok第三种模型出现了
NSOperation + connnetion + NSOperationQueue + COMMENThread
模型三就是AF采用设计方法。
AF 中 NSURLConnection的工作流程代码给出源码
我们需要请求一个网络资源,我们调用AFHTTPRequestOperationManager中的方法
- (AFHTTPRequestOperation *)GET:(NSString *)URLString parameters:(id)parameters success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{ NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"GET" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; [self.operationQueue addOperation:operation]; return operation;}
- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{ AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; operation.responseSerializer = self.responseSerializer; operation.shouldUseCredentialStorage = self.shouldUseCredentialStorage; operation.credential = self.credential; operation.securityPolicy = self.securityPolicy; [operation setCompletionBlockWithSuccess:success failure:failure]; operation.completionQueue = self.completionQueue; operation.completionGroup = self.completionGroup; return operation;}
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{ // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-retain-cycles"#pragma clang diagnostic ignored "-Wgnu" self.completionBlock = ^{ if (self.completionGroup) { dispatch_group_enter(self.completionGroup); } dispatch_async(http_request_operation_processing_queue(), ^{ if (self.error) { if (failure) { dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { id responseObject = self.responseObject; if (self.error) { if (failure) { dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ failure(self, self.error); }); } } else { if (success) { dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ success(self, responseObject); }); } } } if (self.completionGroup) { dispatch_group_leave(self.completionGroup); } }); };#pragma clang diagnostic pop}
这个方法是一个为get的网络请求,AFHTTPRequestOperationManager生成一个AFHTTPRequestOperation,在AFHTTPRequestOperation的构造过程中调用
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure添加完成块。生成完成后加入到自己的operationQueue中在合适的时机分配线程给AFHTTPRequestOperation,调用AFHTTPRequestOperation的start方法
- (void)start { [self.lock lock]; if ([self isCancelled]) { [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; } else if ([self isReady]) { self.state = AFOperationExecutingState; [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; } [self.lock unlock];}start中调用了下面这个函数
[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];这个是中有一个
[[self class] networkRequestThread]
这个是干什么的
+ (NSThread *)networkRequestThread { static NSThread *_networkRequestThread = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{ _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil]; [_networkRequestThread start]; }); return _networkRequestThread;}
这是AFHTTPRequestOperation中的类方法,也就是说调用多次都会只执行一次,产生了一个共有线程 来看AFHTTPRequestOperation让这个共有线程operationDidStart
- (void)operationDidStart { [self.lock lock]; if (![self isCancelled]) { self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; for (NSString *runLoopMode in self.runLoopModes) { [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode]; [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode]; } [self.connection start]; } [self.lock unlock]; dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self]; });}
这个共有线程创建了一个NSURLConnection,然后异步发送请求,那么NSURLConnection的代理回调也会在这个线程中执行,那么多个网络请求实际上都是让这个共有线程发送,然后接受,一个线程来完成多个发送和接受。这里有个问题,请求过多的话是否有问题,一个线程忙的过来吗,答案是可以的,因为都是异步,而且无阻塞。最后完成加载后,执行operation的完成块,执行完成块的线程是系统的一个线程。
思考一下,从并发性的角度来看,AF并没有做什么,根本的并发还是系统底层对NSURLConnection的并发控制, 所谓operationQueue的并发是干什么用的,那要是我仅仅用一个线程来收发,并且没个请求都有相应的存储数据的数据结构和完成块就ok了,干嘛要用queue和NSOperation,既然AF用了就有用,因为他们是因为NSOperation可以cancel,可以暂停,等等,而且这些控制都由queue去管理,这样我们自己写的管理代码就少的多,而且我们管理线程肯定不能优于系统,所以,AF这种设计是非常合理的。
- AFNetWorking的理解
- AFNetworking的介绍与理解
- AFNetWorking 深度理解
- AFNetworking的学习
- AFNetworking的使用
- AFNetWorking 的使用方法
- AFNetWorking的基本使用
- AFNetWorking 的简单使用
- AFNetworking 的使用
- AFNetworking的使用
- AFNetworking 的使用
- AFNetWorking的使用配置
- AFNetworking的使用
- AFNetworking的使用
- AFNetworking的使用
- AFNetWorking 的简单使用
- AFNetWorking的用法
- iOS AFNetworking的使用
- Spring3 整合Hibernate3.5 动态切换SessionFactory (切换数据库方言)
- code使用设置相关-快捷键
- JVM的类加载机制: 加载、连接、初始化。
- Yii中获取参数的方法
- ios开发必备10款第三方类库
- AFNetWorking的理解
- PHP获取当前目录和相对目录的方法
- 通过Maven的版本管理来管理项目公共模块
- HDoj-1863-畅通工程-并查集
- SHC1102无线电子标签技术
- 一些iOS常用的第三方库和控件
- Java内部类总结 (吐血之作)
- 如何生成APNS推送证书的pem文件
- 简单分支体验