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


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339

推荐阅读更多精彩内容