AFNetworking POST操作
网络请求部分,我们上一片分析了GET请求源码部分,通过这篇我们来了解关于POST请求的源码部分,其实POST和GET实现过程是一样的就是中间处理部分会出现略微差异。
POST操作
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary <NSString *, NSString *> *)headers progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters headers:headers uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];
[dataTask resume];
return dataTask;
}
传入的参数和GET方法相同:
- 请求的URL网址;
- 请求头(字典);
- 上传进度;
- 成功回调;
- 失败回调;
同样,返回的是一个NSURLSessionDataTask对象,并且实现了启动任务[dataTask resume];。
进入POST源码我们可以看到,实际上操作是和GET方法调用了一个方法。在这里我们就能清楚的意识到,从这里开始整个流程是一样的,不过对于POST和GET方法是通过之前对Method来区分对待的。
在GET中method传入的是@"GET",而在POST中传入的是@"POST"。
- GET
[self dataTaskWithHTTPMethod:@"GET" URLString:URLString parameters:parameters headers:headers uploadProgress:nil downloadProgress:downloadProgress success:success failure:failure];
- POST
[self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters headers:headers uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];
保存方法
最后到达方法内部,进行保存了HTTP请求方式为POST,此时的method为POST。
mutableRequest.HTTPMethod = method;
AFNetworking应该注意的好的编程方法
这样部分摘自GET和POST共同方法中,我们知道做网络编程中,会出现错误问题,AFNetworking为我们做出了很好的典范,当我们设置了NSError *error后,需要判断如果error出现了错误的情况,如果出现了错误,我们则需要开辟一条新的线程来做错误处理。
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
网络编程遇到线程错误问题是非常常见的,因此,对于错误处理AFNetworking做的非常完善。
反向思考
看到这里,GET和POST的处理方式,是大抵相同的。我们反着梳理一遍思路。首先,要做GET和POST请求,我们需要知道请求网址,因为POST需要的内容比GET多请求头,因此,设计方法时候,将方法安装POST方法设计,当GET调用时候,不需要的地方传入nil即可,此时要能请求POST和GET方法,还需要生成NSURLSessionDataTask,要DataTask就需要NSURLRequest。所以,我们就专门对Request进行一次封装,从用户传入的请求头和请求方法获得信息给Request。这样,Request是带着信息传给NSURLSessionDataTask,这样,就可以生成一个具有这些信息的DataTask。然后,启动任务即可。
或许,你看到这里有疑惑,那成功做的事情和失败做的事情以及进度条是怎么做的呢,的确,设计方法时候,AFNetworking将这三个板块设计成为Block回调,这样就可以等请求完成后,继续运行用户传入的东西。
这些回调原来系统需要使用协议来使用,AFNetworking自然会遵循这一个操作,因此,我们来看看AFNetworking封装的协议。
AFNetworking封装协议
- (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
{
/* 通过dataTask实例化一个delegate对象 */
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
/* 将自身传给delegate对象的管理者 */
delegate.manager = self;
delegate.completionHandler = completionHandler;
/* 任务描述 */
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:dataTask];
/* 传入更新Block和下载Block块 */
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
AFNetworking创建一个AFURLSessionManagerTaskDelegate来管理协议,这个协议继承了NSURLSessionTaskDelegate,NSURLSessionDataDelegate,NSURLSessionDownloadDelegate这三个我们经常使用的三个协议。
@property (nonatomic, weak) AFURLSessionManager *manager; //url话语管理者
@property (nonatomic, strong) NSMutableData *mutableData; //数据
@property (nonatomic, strong) NSProgress *uploadProgress; //更新进度
@property (nonatomic, strong) NSProgress *downloadProgress; //下载进度
@property (nonatomic, copy) NSURL *downloadFileURL; //下载文件的路径
AFURLSessionManagerTaskDelegate将存储每一个协议内容,包括上传进度,下载进度,下载文件路径等。
在设置协议中,有趣的是,AFNetworking向我们展示了区别于RAC锁住线程的方法。
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
[self.lock lock];
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
利用NSLock来锁住线程和释放线程操作。通过字典存储任务标识。为每个任务添加了通知。
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
在这一步里面也进行了计算进度的操作。
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
至此,我们已经分析了大部分源码了,如果有兴趣的话,可以放下在AFNetworking中有对Delete实现的大量封装,这一个封装操作,下一篇会做详细介绍,来帮助梳理如何学习AFNetworking一样封装Delegate。
中文源码下载
AFNetworking中文源码: GitHub