前言
公司最近剛剛趕完一個(gè)版本需求粟耻,準(zhǔn)備對(duì)AFNetworking進(jìn)行升級(jí)。其實(shí)年前就做過這方面研究眉踱,當(dāng)時(shí)是因?yàn)橛袀餮?017年后蘋果要求升級(jí)https而老的網(wǎng)絡(luò)底層不支持挤忙,必須升級(jí)。后來(lái)因?yàn)樾滦枨蟊容^趕勋锤,又在網(wǎng)上找到可靠消息說網(wǎng)上都是謠傳并沒有強(qiáng)制升級(jí)于是就擱置了下來(lái)饭玲。
簡(jiǎn)介
AFNetworking是對(duì)IOS本身網(wǎng)絡(luò)請(qǐng)求的封裝,有兩種方式NSURLConnection和NSURLSession叁执。
因?yàn)锳FNetworking1.0就是構(gòu)建于NSURLConnection之上的茄厘,等到AFNetworking2.0才NSURLSession的方式矮冬,之后的AFNEtworking3.0更去掉了NSURLConnection的方式。關(guān)于原因可以點(diǎn)擊這里次哈。
所以這一次我的主要任務(wù)就是從之前的NSURLConnection(AFHTTPRequestOperationManager)升級(jí)到NSURLSession(AFHTTPSessionManager)胎署。
當(dāng)前網(wǎng)絡(luò)層
剛開始我得先把當(dāng)前的網(wǎng)絡(luò)層理一下,看下哪些地方用到網(wǎng)絡(luò)請(qǐng)求窑滞。最后發(fā)現(xiàn)也復(fù)雜琼牧,一共兩種不一樣的地方:
1.最主要的一個(gè)就是對(duì)一般網(wǎng)絡(luò)POST請(qǐng)求的封裝。
2.上傳一些諸如圖片哀卫、音頻等文件的PUT請(qǐng)求巨坊。
看上去挺簡(jiǎn)單的,但因?yàn)榇a經(jīng)過多代人之手此改,難免有些冗余代碼質(zhì)量也不是特別高趾撵,就像上傳附件的封裝就有兩份在程序中都有用到,為了盡量不產(chǎn)生新問題我也就對(duì)它們都做修改共啃。
下面是之前的實(shí)現(xiàn)方式的主要流程占调,一些代碼上的坑我就不放出來(lái)了。
1.首先是一般網(wǎng)絡(luò)POST請(qǐng)求的封裝移剪。
(1)首先是單例的實(shí)現(xiàn)基礎(chǔ)設(shè)置:
+ (instancetype) sharedClient{
static NetworkManager *_sharedClient = nil;
static dispatch_once_t _onceTocken;
dispatch_once(&_onceTocken, ^{
if (appDelegate.apiBaseUrlStr) {
_sharedClient = [[NetworkManager alloc] initWithBaseURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@",appDelegate.apiBaseUrlStr]]];
} else {
_sharedClient = [[NetworkManager alloc] initWithBaseURL:[NSURL URLWithString:@"(null)"]];
}
_sharedClient.llOperationQueue = [[NSOperationQueue alloc] init];
//最大并發(fā)數(shù)
_sharedClient.llOperationQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;
[_sharedClient.requestSerializer setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[_sharedClient.requestSerializer setValue:ApiVersion forHTTPHeaderField:@"User-Agent"];
[_sharedClient.requestSerializer setTimeoutInterval:30];
_sharedClient.bstart = NO;
_sharedClient.apiCount = 0;
});
return _sharedClient;
}
(2)POST請(qǐng)求對(duì)外接口:
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nonnull))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
if (![CommonClass checkNetworkRechable]) {
failure(nil,[NSError errorWithDomain:@"www.mHealth.com" code:-1009 userInfo:nil]);
return nil;
}
if((!appDelegate.apiBaseUrlStr || appDelegate.apiBaseUrlStr.length < 1) && !_bstart)
{
#ifdef DEBUG_MODE
NSLog(@"No baseurl, need network access");
#endif
[self.llOperationQueue setSuspended:true];
LandbalancerSessionOperation *llsessionOperation = [[LandbalancerSessionOperation alloc] initWithURLString:URLString parameters:parameters success:success failure:failure];
[self.llOperationQueue addOperation:llsessionOperation];
_bstart = true;
[self requestApi];
return nil;
}
else
{
return [super POST:URLString parameters:parameters progress:uploadProgress success:success failure:failure];
}
}
這邊有個(gè)判斷究珊,如果沒有baseurl,則要把當(dāng)次請(qǐng)求先掛起纵苛,先去請(qǐng)求version接口剿涮,完成后再開始當(dāng)次請(qǐng)求。
2.附件上傳
我們這邊上傳附件的流程是這樣的赶站,先進(jìn)行POST請(qǐng)求將我們拼接好的文件名和文件大小給云端幔虏,云端這時(shí)候會(huì)返回我們需要上傳到的url,我們?cè)偻ㄟ^這個(gè)url進(jìn)行PUT上傳贝椿。
(1)POST請(qǐng)求將文件名和長(zhǎng)度給云端:
#pragma mark - NSOperation
-(void)main
{
[self.lock lock];
if(!self.file.rawData)
{
return;
}
NSUInteger size = self.file.rawData.length;
if (size <= 0)
{
// [self removeOperationFromDB];
return;
}
if(!self.file.key || self.file.key.length < 1)
{
return;
}
NSMutableDictionary *parameterMDic = [[NSMutableDictionary alloc] init];
[parameterMDic setObject:[NSNumber numberWithInteger:size] forKey:@"size"];
[parameterMDic setObject:self.file.key forKey:@"filename"];
[parameterMDic setObject:[appDelegate.userDefaults objectForKey:AccessToken] forKey:AccessToken];
[[NetworkManager sharedClient] POST:API_ATTACHMENT parameters:parameterMDic success:^
(AFHTTPRequestOperation *__unused task, id JSON){
#ifdef DEBUG_MODE
#endif
[self completionBlock:API_ATTACHMENT withData:JSON withUserInfo:nil];
}failure:^
(AFHTTPRequestOperation *__unused task, NSError *error){
#ifdef DEBUG_MODE
#endif
[self failedBlock:API_ATTACHMENT withError:error withUserInfo:nil];
}];
[self.lock unlock];
}
(2)這里把云端返回?cái)?shù)據(jù)統(tǒng)一判斷想括,未完成就進(jìn)行PUT請(qǐng)求上傳文件,直到完成:
-(void)dealAttachmentResponse:(NSDictionary *)responseDic
{
[self.lock lock];
NSString *finishStr = [responseDic objectForKey:@"finished"];
if ([CommonClass bNull:(NSNull *)finishStr] && finishStr)
{
_finishStr = finishStr;
}
else
{
_finishStr = nil;
}
NSNumber *lenNum = [responseDic objectForKey:@"len"];
NSString *methodStr = [responseDic objectForKey:@"method"];
if ([CommonClass bNull:(NSNull *)methodStr] && methodStr)
{
_methodStr = methodStr;
}
else
{
_methodStr = nil;
}
NSNumber *offNum = [responseDic objectForKey:@"off"];
NSString *urlStr = [responseDic objectForKey:@"url"];
if ([CommonClass bNull:(NSNull *)urlStr] && urlStr)
{
_urlStr = urlStr;
}
else
{
_urlStr = nil;
}
// _urlStr = [_urlStr stringByReplacingOccurrencesOfString:@"db.mcloudlife.com" withString:@"115.236.76.184"];
if ([_finishStr isEqualToString:@"Y"] || [lenNum integerValue] <= 0)
{
//上傳完成
// NSString *imgName = [urlStr lastPathComponent];
// self.uploadOneFileSucceeded(imgName, self.fileIndex, self.file.key);
self.uploadOneFileSucceeded(_urlStr, self.fileIndex, self.file.key);
return;
}
NSRange range = NSMakeRange([offNum integerValue], [lenNum integerValue]);
NSData * data = [self getUploadImgData:self.file.rawData withRange:range];
NSInputStream *inputStream = [[NSInputStream alloc] initWithData:data];
[self httpRequestThroughPut:inputStream];
[self.lock unlock];
}
- (NSData *)getUploadImgData:(NSData *)imgData withRange:(NSRange)range
{
NSUInteger length = [imgData length];
if (length < (range.location + range.length)) {
return nil;
}
NSData *subData = [imgData subdataWithRange:range];
return subData;
}
(3)PUT請(qǐng)求上傳數(shù)據(jù)烙博,失敗重試瑟蜈,成功則再以上面的方法判斷是否完成。
#pragma mark - NetWork_Upload
-(void)httpRequestThroughPut:(NSInputStream *)inputStream
{
if (inputStream && _urlStr)
{
AFHTTPRequestOperationManager *requestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:nil];
//設(shè)置httpHeader
[requestOperationManager.requestSerializer setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[requestOperationManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[requestOperationManager.requestSerializer setValue:[NSString stringWithFormat:@"mCloud %@",[appDelegate.userDefaults objectForKey:AccessToken]] forHTTPHeaderField:@"Authorization"];
[requestOperationManager.requestSerializer setValue:@"db.mcloudlife.com" forHTTPHeaderField:@"Host"];
//設(shè)置超時(shí)時(shí)間
[requestOperationManager.requestSerializer setTimeoutInterval:-1];
//put請(qǐng)求
AFHTTPRequestOperation *requestOperation = [requestOperationManager PUT:_urlStr parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (![NetworkErrorDeal getErrorMsgWithResponseData:responseObject])
{
if(![responseObject isKindOfClass:[NSDictionary class]])
{
return;
}
[self dealResponse:responseObject];
}
else
{
//嘗試重新請(qǐng)求
if(_retryCount <= 0)
{
return ;
}
_retryCount--;
dispatch_queue_t queue= dispatch_queue_create("dealFileAttachmentResponse", NULL);
dispatch_async(queue, ^{
[self httpRequestThroughPut:inputStream];
});
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if(_retryCount <= 0)
{
return ;
}
_retryCount--;
dispatch_queue_t queue= dispatch_queue_create("dealImageAttachmentResponse", NULL);
dispatch_async(queue, ^{
[self httpRequestThroughPut:inputStream];
});
}];
__block AFHTTPRequestOperation *progressOperation = requestOperation;
[requestOperation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
// }]
// [requestOperation setUploadProgressBlock:^(NSUInteger bytesWritten, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite) {
double percent = totalBytesWritten * 1.0 / self.file.fileSize;
if (self.uploadOneFileProgress) {
self.uploadOneFileProgress(progressOperation, self.fileIndex, percent);
}
}];
//設(shè)置httpbodystream
[requestOperation setInputStream:inputStream];
}
}
好了渣窜,這些就是之前的網(wǎng)絡(luò)層铺根,等我給測(cè)試進(jìn)行整體測(cè)試如果沒問題的話,我會(huì)在下一篇記錄主要的修改乔宿。
另外大家如果有關(guān)于升級(jí)AFNetworking3.0的問題的話可以留下評(píng)論位迂,指教不敢當(dāng),互相討論吧:)