AFNetworking源码阅读2——核心

前言

AFNetworking源码阅读1中,我们已经阅读完了AFHTTPSessionManager类。本篇我们阅读其父类AFURLSessionManager。该类是整个框架的核心。


源码:AFURLSessionManager

先来看看头文件AFURLSessionManager.h

屏幕快照 2016-10-10 下午2.06.59.png

该类代码太长,我们从头至尾一段一段看。先看头部的属性部分:

@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>

//  The managed session.
@property (readonly, nonatomic, strong) NSURLSession *session;

//  The operation queue on which delegate callbacks are run.
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue; // 代理回调所运行的操作队列

@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer; 

@property (nonatomic, strong) AFSecurityPolicy *securityPolicy; // 安全策略

@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager; 

// The data, upload, and download tasks currently run by the managed session.
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;

@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;

@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;

@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;

// The dispatch queue for `completionBlock`. If `NULL` (default), the main queue is used.
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;

// The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used.
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;

@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;

第一个属性session就是该类所管理的session;operationQueue是代理回调所运行的操作队列;responseSerializer是解析网络返回数据的序列化器,它是实现了AFURLResponseSerialization协议的任意类型;securityPolicy有关网络安全连接的安全策略,这个后面还要继续研究;reachabilityManager是检测网络状态的检测器,后面也会继续研究;tasks代表管理的session此时正在运行的data task,upload task,download task们;completionQueuecompletionBlock的dispatch queue,而completionGroupcompletionBlock的dispatch group。

属性看完,该轮到初始化方法了:

#pragma mark - init method
- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks; // 选择性地取消挂起的task

可以看到,第一个方法为初始化方法,第二个方法为选择性的取消挂起的session task,只需要传入某个挂起的task为参数,便可取消该task。
这里需要多说一句的是初始化方法后面有个标识符:NS_DESIGNATED_INITIALIZER,它代表什么意思呢?它呀,意为“被设计的初始化器”,“被指定的初始化方法”。
详情请查看:iOS: 聊聊 Designated Initializer(指定初始化函数)
正确使用NS_DESIGNATED_INITIALIZER

接下来到了核心方法部分了:

#pragma mark - create task from request

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler DEPRECATED_ATTRIBUTE;

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                               uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                             downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler;

// 为一个本地文件通过构成一个特定request,从而创建uploadTask
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromFile:(NSURL *)fileURL
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError  * _Nullable error))completionHandler;

可以看到以session task类型的不同,提供了不同的方法,并且同一类型的session task下也可能提供多个不同场景的方法。(篇幅有限,部分方法省略)
多说一句:DEPRECATED_ATTRIBUTE标识符的意思是慢慢弃用的属性或接口,如果我们使用了,在xcode中就会出现警告⚠️信息。

接下来是这两个方法:

#pragma mark - get progress for task

- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;

- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;

这两个方法看名字就可以明白其意义:获得某个task的进度。

再接着就是session delegate callback的setter方法了,它们是和session以及session task的代理方法是一一对应的。在这里不作说明,等到阅读到代理方法时就明白了。

接下来就是最后一部分代码:


FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidResumeNotification; // Posted when a task resumes.

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteNotification; // Posted when a task finishes executing

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidSuspendNotification; // Posted when a task suspends its execution.

FOUNDATION_EXPORT NSString * const AFURLSessionDidInvalidateNotification; // Posted when a session is invalidated.

FOUNDATION_EXPORT NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification; // Posted when a session download task encountered an error when moving the temporary download file to a specified destination.

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseDataKey;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteAssetPathKey;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteErrorKey;

上面的代码,声明了一些用于通知的全局常量。说起全局常量的使用方法:先在.h文件中用** extern声明此全局常量,然后在.m文件中定义该全局常量。《52个有效方法》笔记1——熟悉Objective-C。但在这里声明时并没有用extern**,而是用了FOUNDATION_EXPORT,关于它的解释见:FOUNDATION_EXPORT 或#define 或 extern


现在开始看AFURLSessionManager.m
代码太长太长,我们一段一段来分析。先来看看Extension部分:

@interface AFURLSessionManager ()
@property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;
@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
@property (readwrite, nonatomic, strong) NSURLSession *session;
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
@property (readonly, nonatomic, copy) NSString *taskDescriptionForSessionTasks;
@property (readwrite, nonatomic, strong) NSLock *lock;
@property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid;
@property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge;
@property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession;
@property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge;
@property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse;
@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData;
@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume;
@end

这里又定义了一个readwrite的session作为私有属性。而在头文件中定义的session属性是readonly的。这么做更安全,在内部我们可对该属性进行读写操作,而暴露给外部时,使用者只能read。
mutableTaskDelegatesKeyedByTaskIdentifier属性是个可变字典。该属性有大用处,以taskIdentifier作为key,以task delegate为value,将task和其delegate一对一绑定,后面还需细说。
然后后面均为回调block的属性。

然后我们看看初始化方法:

- (instancetype)init {
    return [self initWithSessionConfiguration:nil];
}

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }

    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }

    /*
     初始化各个属性
     */
    self.sessionConfiguration = configuration;

    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;

    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

    self.responseSerializer = [AFJSONResponseSerializer serializer]; // 默认的反序列化类型是AFJSONResponseSerializer

    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

#if !TARGET_OS_WATCH
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif

    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;

    // 遍历所管理的session的task,给每个task设置一个delegate
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        for (NSURLSessionDataTask *task in dataTasks) {
            [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
        }

        for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
            [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
        }

        for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
            [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
        }
    }];

    return self;
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

在初始化方法中可以看到。首先,若初始化时传入的参数configuration为nil,则默认初始化为defaultSessionConfiguration;然后就是初始化各个属性了,session属性是通过NSURLSession的类方法sessionWithConfiguration:delegate:delegateQueue:方法来初始化的,设delegate为self。当时阅读代码时,始终有个疑问:本类实现了四个协议,第一个为session的协议,是在这里设置delegate为self了。后面三个协议我始终找不到在哪设置session task的delegate为self的地方,觉得很疑惑,这没地方设置过代理,为什么实现了代理方法?代理方法怎么会执行呢?后面我从网上才看到,只要设置了session的delegate,那也等同于设置该session创建的session task的代理。还因这个问题找了半天代码...
初始化方法的最后遍历了所管理的session的task,给每个task设置了一个delegate。关于设置delegate这个方法的实现细节,我们暂且等到下文详解。但这里我也有个疑惑:这里是初始化方法,session才刚刚被初始化,该session应当还没有对应的session task啊,为何要遍历其session task?会有吗?这个问题百思不得其解,希望哪位大兄弟看到能解惑...

然后我们看这个类最重要的方法:

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
}

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                               uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                             downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler {

    // 1.调用NSURLSession的实例方法dataTaskWithRequest生成dataTask
    __block NSURLSessionDataTask *dataTask = nil;
    url_session_manager_create_task_safely(^{
        dataTask = [self.session dataTaskWithRequest:request]; 
    });

    // 2.为该dataTask设置delegate,将dataTask与delegate一一绑定
    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}

看到这个方法名,我们大概能猜到该方法内部的实现步骤:因为参数为request,返回值时dataTask,那很可能是完成了由request生成dataTask的动作。但是应该还不仅仅是这样,因为该方法还有block回调,block回调的内容是怎么来的呢?
好了,一看代码果然和我们猜的差不多。这里面主要有两个步骤:
1.调用NSURLSession的实例方法dataTaskWithRequest:生成dataTask。
url_session_manager_create_task_safely是为了修复某个bug,我们在此不必纠结。
2.为该dataTask设置delegate,将dataTask与delegate一一绑定。并且通过block传递出来该请求任务的一些进度、数据、错误信息等。

我们看看第二个步骤的方法实现:

- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
                uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
              downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
             completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    /*
     创建一个AFURLSessionManagerTaskDelegate代理类的对象,并为几个属性赋值。然后调用setDelegate:forTask:将其和dataTask绑定
     */
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    [self setDelegate:delegate forTask:dataTask]; // 将delegate和task绑定的核心

    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}

可以看到,里面创建了一个AFURLSessionManagerTaskDelegate代理类的对象,并为几个属性赋值(主要为block回调属性)。然后调用setDelegate:forTask:将此delegate实例对象和该task绑定。但实现此功能的是setDelegate:forTask:方法。

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    NSParameterAssert(task);
    NSParameterAssert(delegate);

    [self.lock lock];
    // 将task和代理类绑定,task的taskIdentifier作为字典的key,delegate作为字典的value
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    [delegate setupProgressForTask:task]; // 该方法主要是设置两个NSProgress类型的变量uploadProgress和downloadProgress的属性
    [self addNotificationObserverForTask:task]; // 给该task添加两个KVO事件
    [self.lock unlock];
}

该方法内部有三个步骤:
1.将task的taskIdentifier作为键,将delegate作为值,赋给可变字典mutableTaskDelegatesKeyedByTaskIdentifier。完成delegate和task的一对一绑定;
2.调用delegate的setupProgressForTask:方法。由task设置delegate对象的uploadProgressdownloadProgress属性的属性值。
3.给该task添加两个观察(启动和暂停)。
关于步骤一,相当于对mutableTaskDelegatesKeyedByTaskIdentifier可变字典的set操作,当然还有与此对应的get操作,获得某task对应的delegate。

- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
    NSParameterAssert(task);

    AFURLSessionManagerTaskDelegate *delegate = nil;
    [self.lock lock];
    delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
    [self.lock unlock];

    return delegate;
}

该类中有多处用到了get操作,比如:
移除某个task对应的delegate。首先通过delegateForTask:方法获得此delegate,然后移除此task的进度观察,移除启动和暂停的观察,并最终从字典中删除此task。

- (void)removeDelegateForTask:(NSURLSessionTask *)task {
    NSParameterAssert(task);

    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
    [self.lock lock];
    [delegate cleanUpProgressForTask:task];
    [self removeNotificationObserverForTask:task];
    [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
    [self.lock unlock];
}

又比如:
** 获得该task的上传或下载进度。**

- (NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task {
    return [[self delegateForTask:task] uploadProgress];
}

- (NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task {
    return [[self delegateForTask:task] downloadProgress];
}

再比如,我们待会会讲到的,在该类实现的代理方法里,有时还需要调用在其代理类AFURLSessionManagerTaskDelegate中实现的代理方法。此时就需要调用delegateForTask:方法得到相应的delegate。

关于步骤三的实现详情:

- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
}

为task添加启动和暂停的通知,当该task启动时就执行taskDidResume:方法,当该task暂停时就执行taskDidSuspend:方法。

- (NSString *)taskDescriptionForSessionTasks {
    return [NSString stringWithFormat:@"%p", self];
}

- (void)taskDidResume:(NSNotification *)notification {
    NSURLSessionTask *task = notification.object;
    if ([task respondsToSelector:@selector(taskDescription)]) {
        if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
            });
        }
    }
}

taskDidResume:taskDidSuspend:两个方法的代码是什么意思,没明白...不应该是在某个地方发出了通知,然后在这观察到了,然后就会执行这两个方法吗?那为什么,在这俩方法里还post notification?💔
更新:taskDidResume:taskDidSuspend:分别是AFNSURLSessionTaskDidSuspendNotificationAFNSURLSessionTaskDidSuspendNotification的回调方法,我们上面说其意分别代表为task启动和暂停。为了确认,我们在代码中找找post出这俩通知的地方。

- (void)af_resume {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    [self af_resume];
    
    if (state != NSURLSessionTaskStateRunning) {
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
    }
}

- (void)af_suspend {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    [self af_suspend];
    
    if (state != NSURLSessionTaskStateSuspended) {
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
    }
}

af_resumeaf_suspend是什么方法呢?我们预期它应该是在该task执行resumesuspend方法后便立即post通知的。我们寻根溯源,继续找af_resumeaf_suspend俩方法是在哪触发的:

+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass {
    Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
    Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));

    if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) {
        af_swizzleSelector(theClass, @selector(resume), @selector(af_resume));
    }

    if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) {
        af_swizzleSelector(theClass, @selector(suspend), @selector(af_suspend));
    }
}

可以看到那俩方法大量基本出现在swizzleResumeAndSuspendMethodForClass:这个方法中,继续找寻根溯源,原来这个方法是在_AFURLSessionTaskSwizzling这个类的load方法中调用的。_AFURLSessionTaskSwizzling这个类干了什么,我们研究研究。

屏幕快照 2016-10-13 上午10.57.48.png

说到这我们得说说Method Swizzing,我在这篇文中已经说过:《52个有效方法》笔记3——探究runtime
摘录如下:

OC对象都有一个isa指针,该指针指向一个方法调度表,它存储着该对象的方法。并且,它的形式是键值对,key为SEL,value为IMP。
既然如此,那我们可以在SEL和IMP的映射上做文章。也就是说我可以人为地改变SEL和IMP之间的映射关系。
这样做有什么意义吗?嗯,意义很大。我们可以把原有的类和我们自定义类的映射对调,那这样,即使我们在代码里调用的是原有类的方法,但暗地里却神不知鬼不觉地在执行我们自定义的方法。哈哈,说得有些玄乎了。
其实,在实践中Method Swizzing可以完成AOP或者对原有类的拓展。

在本例中,就将原始的resumesuspend俩方法的实现IMP调包了,调成了_AFURLSessionTaskSwizzling这个类自己实现的af_resumeaf_suspend。而在af_resumeaf_suspend俩方法里,我们分别post出了相应的通知。如以一来,即便是程序是在调用原始的resume方法,但程序实际上却神不知鬼不觉地执行了af_resume,发送了通知出来。

另外之前看这块代码时觉得蒙圈的一个地方是把````taskDidResume:taskDidSuspend:俩方法里发送的通知名字看错了😅。在这俩回调方法里post出的是AFNetworkingTaskDidResumeNotificationAFNetworkingTaskDidSuspendNotification通知,主要是用于通知UI层的。并不是AFNSURLSessionTaskDidResumeNotificationAFNSURLSessionTaskDidSuspendNotification``通知,当时太蒙圈了,怎么在观察到通知的回调里再次发出通知😅。


现在,我们来看看在该类中实现的代理方法。在该类中实现了4个协议的代理方法。
有关这些代理方法的含义及具体实现的讲解这篇文章讲解的很详细,在此我不再写了:
AFNetworking源码阅读(三)

但是还是有几个点需要说明一下。
首先,就是我们可以看到在这些代理方法的实现里,很多都会先判断有无与代理方法对应的自定义的block回调(这个我们在前面讲头文件时提到过,那些block都是与代理方法对应的)。若有,则调用自定义的block,在定义的block回调里做相应的处理。
说起自定义的block回调。若按我平时的写法习惯,我一般都是直接在头文件中定义为公开属性。这样在.m文件里直接调用就行。但是这里的源码却不是,它没有在头文件中定义为公开的属性,而是在.m的Extension中定义为私有属性,在.h头文件中以定义的setXXX方法的形式暴露其接口,然后又在.m文件的方法体中赋给了私有block属性。这和直接在头文件定义为block属性其实应该是等效的,之所以这么写,难道是这样更安全?

其次,在阅读源码时我一直困惑于一个问题:
既然在创建session时,设self,即AFURLSessionManager为其代理,那为什么还要再来个AFURLSessionManagerTaskDelegate类,在这个代理类中将部分代理方法再实现一遍?
而且这个代理类是和AFURLSessionManager类写在一个文件里的,刚开始读时没注意到,阅读时有种剪不断理还乱的感觉。所以这个问题一直困惑不解,所以我百度了又百度,终于看到别人的一篇文章有解释这个问题。摘录如下:
AFNetWorking(3.0)源码分析(二)——AFURLSessionManager

AFURLSessionManager 与 AFURLSessionManagerTaskDelegate 的分工

到这里我们可以想一想,既然NSURLSession的delegate是AFURLSessionManager对象,那么为什么不在AFURLSessionManager中处理所有的事件回调,搞出来一个AFURLSessionManagerTaskDelegate干什么?

我们知道,NSURLSession的回调有很多,而当我们启动一个task,真正想要获取的信息是什么呢?就是网络请求最终所返回的数据(我所进行的网络操作成功或是失败,服务器为我返回的数据)呗! 其它的回调,什么认证质询,task需要新的body stream,什么request即将重定向, 统统都是浮云,都是为了我们能够最终获取到服务器返回的数据所服务的。

另外我们也想要知道我们的网络请求的进度。
总结为两点:

  1. 获取最终返回数据
  2. 获知当前请求的进度

于是,AFNetWorking 便在纷繁复杂的回调处理中,特意抽象出AFURLSessionManagerTaskDelegate,用于应付网络返回数据的处理(包括保存中间值,序列化返回值,错误处理)和网络请求进度。
这样做可以使代码结构更分明,逻辑更清晰。

真是谢谢这位博主。说起来其实就是分工,将我们最终感兴趣的东西(服务器返回的数据,进度,错误信息等)抽离在代理类中。


结尾

本篇将AFURLSessionManager类说得差不多了,好累,洗洗睡。明天写下一篇,整理整理AFURLSessionManagerTaskDelegate类。

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

推荐阅读更多精彩内容