1、AFNetworking的简单使用
大家使用此开源框架一般是用来进行网络请求的,下面是一个简单的例子
//创建一个管理者对象
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//进行超时设置
manager.requestSerializer.timeoutInterval = 10;
//序列化模式设置(默认是Json)
manager.responseSerializer = [AFJSONResponseSerializer serializer];
//发送一个GET请求
[manager GET:urlString
parameters:nil
success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
NSLog(@"加载成功");
}
failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
NSLog(@"加载失败");
}];
2、大致框架
该开源框架是基于NSURLConnection 和 NSURLSession 进行开发的。其中有两个管理类:AFHTTPRequestOperationManager 和 AFHTTPSessionManager。另外一个主要的类是AFURLConnectionOperation,这是一个自定义的NSOperation,用来进行网络请求任务,回调,传到主线程。
3、AFURLConnectionOperation
首先讨论的是线程。我们进行网络请求无外乎以下几点:
1)主线程同步请求:这会堵塞主线程,一般没人采用。
2)主线程调用异步请求:NSURLConnection 在主线程Runloop触发回调事件,主线程的Mode(�可以理解为状态吧)有两个默认的:NSDefaultRunLoopMode,记录平时的状态和UITrackingRunLoopMode,追踪ScrollView滑动时的状态。如果你想随时随刻都接受NSURLConnection的回调,就必须将设置在NSRunLoopCommonModes
状态下,因为如果一直处于滑动状态的话,就不能处理回调。但是这样又会影响动画效果。
3)子线程调用同步请求:此时进行请求虽然不会影响主线程的状态,但是处理一条网请求就要占据一条线程,该线程一直阻塞直到进行回调,若请求比较多的话,就会占据多条线程,资源浪费。
4)子线程调用异步请求:在这种情况下可以设置一条常驻子线程,用来进行网络请求的回调,这样多个网路请求进行请求时,回调都在统一的一个子线程,之后在传到主线程,也不会影响到主线程。比起上面的方式3),有不小的优势。
该框架采用的就是方式4)。源码:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
//创建一个线程 来进行网络活动
+ (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;
}
当一个operation 键入到 queue 中,就会自动调用operation 的 方法:
- (void)start;
该框架的此方法将会在上面创建的线程中创建一个connection请求网络数据,并在该线程中进行回调。并且于此同时创建了一个outputStream,用于进行将收到的数据写进内存。
- (NSOutputStream *)outputStream {
if (!_outputStream) {
self.outputStream = [NSOutputStream outputStreamToMemory];
}
return _outputStream;
}
补充:
operation 里有包含了一个状态机的东西,描述当前operation的状态,用的是KVO进行管理。状态分为
isReady → isExecuting → isFinished
自定义的operation必须加上状态机,否则加入到queue中无法运行。
就像queue中的依赖,A 依赖 B,只有当B中的状态机的状态为isFinished时才会开始执行A。
该框架中的源码如下,
typedef NS_ENUM(NSInteger, AFOperationState) {
AFOperationPausedState = -1,
AFOperationReadyState = 1,
AFOperationExecutingState = 2,
AFOperationFinishedState = 3,
};
- (void)setState:(AFOperationState)state {
if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) {
return;
}
[self.lock lock];
NSString *oldStateKey = AFKeyPathFromOperationState(self.state);
NSString *newStateKey = AFKeyPathFromOperationState(state);
[self willChangeValueForKey:newStateKey];
[self willChangeValueForKey:oldStateKey];
_state = state;
[self didChangeValueForKey:oldStateKey];
[self didChangeValueForKey:newStateKey];
[self.lock unlock];
}
当收到服务器中的数据时候,会调用connection的代理方法:
- (void)connection:(NSURLConnection __unused *)connection
didReceiveData:(NSData *)data;
将受到的数据写进内存中,收完之后,调用
- (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection;
将内存中的数据取出来,关闭connection,该operation状态机状态处于isFinished,并且调用该operation的completionBlock,对收到的数据进行操作。
该框架对block的操作经常看到这样类型的:
__weak __typeof(self)weakSelf = self;
[super setCompletionBlock:^ {
__strong __typeof(weakSelf)strongSelf = weakSelf;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop
dispatch_group_async(group, queue, ^{
block();
});
dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
[strongSelf setCompletionBlock:nil];
});
}];
}
创建一个weakself ,防止block和self之间进行循环引用,造成无法释放。但之后有创建一个strongself防止self指向的对象提前释放(block的执行是异步的,可能block还没有执行完,operation就dealloc了,block内又用到了,作者忽略了循环引用,因为最后这又设置这个block为nil,最终不会造成循环引用)。又因为strongSelf 之后又自动释放了,不会造成循环引用;
网友评论