AFNetworking 源码阅读

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 之后又自动释放了,不会造成循环引用;


你可能感兴趣的:(AFNetworking 源码阅读)