https://github.com/starainDou 歡迎點(diǎn)星
AFNetWorking
- 本段代碼為總結(jié)知識點(diǎn)
// AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; //推薦下面方式
AFHTTPSessionManager *manager =[[AFHTTPSessionManager alloc] initWithBaseURL:BaseURL];
// 設(shè)置請求頭
[manager.requestSerializer setValue:@"en" forHTTPHeaderField:@"locale"];
// 請求序列化
manager.requestSerializer = [AFJSONRequestSerializer serializer];
// 設(shè)置超時(shí)時(shí)間
manager.requestSerializer.timeoutInterval = 30.f;
// 響應(yīng)內(nèi)容序列化
manager.responseSerializer = [AFJSONResponseSerializer serializer];
// 支持的內(nèi)容類型
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects: @"application/json", @"text/json", @"text/plain",@"text/html", nil];
// 固定參數(shù)可這樣寫
NSDictionary *params = @{@"uid":userId, @"token":token};
// 可選參數(shù)可這樣寫
NSMutableDictionary *params = [NSMutableDictionary dictionary];
if (userId) params[@"uid"] = userId;
if (token) params[@"token"] = token;
// 網(wǎng)絡(luò)請求
[manager POST:url parameters:params constructingBodyWithBlock:^(id formData) {
[formData appendPartWithFileData:UIImageJPEGRepresentation(image, 0.5)
name:@"uploadfile"
fileName: fileName
mimeType:@"image/jpeg"];
} progress:^(NSProgress *uploadProgress) {
} success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"success : %@", responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"error : %@",error.localizedDescription);
}];
NSURLSession
-
NSURLSession 的優(yōu)勢
- NSURLSession 支持 http2.0 協(xié)議
- 在處理下載任務(wù)的時(shí)候可以直接把數(shù)據(jù)下載到磁盤
- 支持后臺上傳/下載
- 同一個(gè) session 發(fā)送多個(gè)請求托修,只需要建立一次連接(復(fù)用了TCP)
- 提供了全局的 session 并且可以統(tǒng)一配置忘巧,使用更加方便
- 下載的時(shí)候是多線程異步處理,效率更高
-
NSURLSessionTask 是一個(gè)抽象類睦刃,常用兩個(gè)子類
- NSURLSessionDataTask: 處理一般的網(wǎng)絡(luò)請求砚嘴,其子類NSURLSessionUploadTask處理上傳請求
- NSURLSessionDownloadTask,主要用于處理下載請求,有很大的優(yōu)勢
GET請求
1.使用 NSURLSession 對象創(chuàng)建 Task
2.執(zhí)行 Task
//創(chuàng)建 NSURLSession 對象
NSURLSession *session = [NSURLSession sharedSession];
/**
根據(jù)對象創(chuàng)建 Task 請求
url 方法內(nèi)部會自動將 URL 包裝成一個(gè)請求對象(默認(rèn)是 GET 請求)
completionHandler 完成之后的回調(diào)(成功或失斏尽)
param data 返回的數(shù)據(jù)(響應(yīng)體)
param response 響應(yīng)頭
param error 錯誤信息
*/
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
//解析服務(wù)器返回的數(shù)據(jù)
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
//默認(rèn)在子線程中解析數(shù)據(jù)
NSLog(@"%@", [NSThread currentThread]);
}];
//發(fā)送請求(執(zhí)行Task)
[dataTask resume];
- POST請求
NSString *str = @"http://doudianyu.com/commetlist/";
// 如果需要中文編碼
NSString *urlPath = [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
//確定請求路徑
NSURL *url = [NSURL URLWithString:urlPath];
//創(chuàng)建可變請求對象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//修改請求方法
request.HTTPMethod = @"POST";
// 設(shè)置請求頭
[request setValue:@"en" forHTTPHeaderField:@"local"];
//設(shè)置請求體
request.HTTPBody = [@"page=0&size=50&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
//創(chuàng)建會話對象
NSURLSession *session = [NSURLSession sharedSession];
// 遮罩
[SVProgressHUD show];
//創(chuàng)建請求 Task
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
//回到主線程更新UI -> 撤銷遮罩
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
});
if (error) {
NSLog(@"提示用戶請求失敗...error:%@",error);
} else {
// JSON解析 蘋果原生效率很高
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
if ([[result objectForKey:@"message"] isEqualToString:@"success"]) {
//獲取數(shù)據(jù)->主線程更新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSDictionary *data = [result objectForKey:@"data"];
});
}else{
NSLog(@"未查到信息....");
}
NSLog(@"請求成功... %@",result);
}
}];
//發(fā)送請求
[dataTask resume];
- NSURLSessionDataTask 設(shè)置代理發(fā)送請求
1.創(chuàng)建 NSURLSession 對象設(shè)置代理
2.使用 NSURLSession 對象創(chuàng)建 Task
3.執(zhí)行 Task
//確定請求路徑
NSURL *url = [NSURL URLWithString:@"http://doudianyu.com/commetlist/"];
//創(chuàng)建可變請求對象
NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
//設(shè)置請求方法
requestM.HTTPMethod = @"POST";
//設(shè)置請求體
requestM.HTTPBody = [@"page=0&size=50&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
//創(chuàng)建會話對象也颤,設(shè)置代理
/**
第一個(gè)參數(shù):配置信息
第二個(gè)參數(shù):設(shè)置代理
第三個(gè)參數(shù):隊(duì)列竭沫,如果該參數(shù)傳遞nil 那么默認(rèn)在子線程中執(zhí)行
*/
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self delegateQueue:nil];
//創(chuàng)建請求 Task
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestM];
//發(fā)送請求
[dataTask resume];
4.遵守協(xié)議谎势,實(shí)現(xiàn)代理方法(常用的有三種代理方法)
#pragma mark 接收到服務(wù)器響應(yīng)的時(shí)候調(diào)用
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
NSLog(@"子線程中執(zhí)行 -- %@", [NSThread currentThread]);
self.dataM = [NSMutableData data];
// 默認(rèn)情況下不接收數(shù)據(jù),必須告訴系統(tǒng)是否接收服務(wù)器返回的數(shù)據(jù)
completionHandler(NSURLSessionResponseAllow);
}
#pragma mark 接受到服務(wù)器返回?cái)?shù)據(jù)的時(shí)候調(diào)用,可能被調(diào)用多次
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
//拼接服務(wù)器返回的數(shù)據(jù)
[self.dataM appendData:data];
}
#pragma mark 請求完成或者是失敗的時(shí)候調(diào)用
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
//解析服務(wù)器返回?cái)?shù)據(jù)
NSLog(@"%@", [[NSString alloc] initWithData:self.dataM encoding:NSUTF8StringEncoding]);
}
5.設(shè)置代理之后的強(qiáng)引用問題
- NSURLSession對象使用時(shí)若設(shè)置了代理掷伙,session會對代理對象保持一個(gè)強(qiáng)引用寒波,合適的時(shí)候應(yīng)主動釋放
- dealloc中調(diào)用 invalidateAndCancel或finishTasksAndInvalidate方法釋放對代理對象的強(qiáng)引用
1.invalidateAndCancel 方法直接取消請求然后釋放代理對象
2.finishTasksAndInvalidate 方法等請求完成之后釋放代理對象
[self.session finishTasksAndInvalidate];
-(void)dealloc
{
//注意:在不用的時(shí)候一定要調(diào)用該方法來釋放,不然會出現(xiàn)內(nèi)存泄露問題
//方法一:取消所有過去的會話和任務(wù)
[self.session invalidateAndCancel];
//方法二:可在釋放時(shí)做一些操作
[self.session resetWithCompletionHandler:^{
// 釋放時(shí)做的操作
}];
}
- NSURLSessionDataTask 簡單下載
[[[NSURLSession sharedSession] dataTaskWithURL:imgURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = [UIImage imageWithData:data];
});
}] resume];
- NSURLSessionDownloadTask 簡單下載
1.使用 NSURLSession 對象創(chuàng)建下載請求
2.在下載請求中移動文件到指定位置
3.執(zhí)行請求
4.代理方法監(jiān)聽下載進(jìn)度
//優(yōu)點(diǎn):該方法內(nèi)部已經(jīng)完成了邊接收數(shù)據(jù)邊寫沙盒的操作,解決了內(nèi)存飆升的問題
NSURLSessionDownloadTask *downTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
// 默認(rèn)存儲到臨時(shí)文件夾 tmp 中,需要剪切文件到 cache
NSLog(@"目標(biāo)位置%@", location);
NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
// fileURLWithPath:有協(xié)議頭; URLWithString:無協(xié)議頭
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
}];
//發(fā)送請求
[downTask resume];
- NSURLSessionDataTask和NSURLSessionDownloadTask下載對比
- DataTask可以實(shí)現(xiàn)離線斷點(diǎn)下載臭增,但是代碼相對復(fù)雜
- DownloadTask可斷點(diǎn)下載但不能離線斷點(diǎn)下載拗窃,邊接收邊寫入沙盒解決下載大文件內(nèi)存飆升問題
NSURLConnection
- first deprecated in iOS 9.0
- 文件上傳
FileUpload.h
#import <Foundation/Foundation.h>
@interface FileUpload : NSObject
@end
FileUpload.m
// iOS post方式上傳文件
#import "FileUpload.h"
@implementation FileUpload
+ (void)uploadFiles:(NSArray *)files msgId:(NSString *)msgId obj:(id)obj userid:(NSString *)userid {
// 分界線的標(biāo)識符
for (NSMutableDictionary *filedic in files) {
NSString *TWITTERFON_FORM_BOUNDARY = @"AaB03x";
// 根據(jù)url初始化request
NSString* URL = [NSString stringWithFormat:@"http://%@%@",NSLocalizedString(@"MQTT_IP", @""),NSLocalizedString(@"im_uploadfileURL", @"")];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URL]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:10];
// 分界線 --AaB03x
NSString *MPboundary=[[NSString alloc]initWithFormat:@"--%@",TWITTERFON_FORM_BOUNDARY];
// 結(jié)束符 AaB03x--
NSString *endMPboundary=[[NSString alloc]initWithFormat:@"%@--",MPboundary];
// 要上傳的文件
NSData *data = [NSData dataWithContentsOfFile:[filedic objectForKey:@"filepath"]];
// http body的字符串
NSMutableString *body=[[NSMutableString alloc]init];
// 參數(shù)的集合普通的key-value參數(shù)
body = [self setParamsKey:@"uptype" value:@"1" body:body];
body = [self setParamsKey:@"sid" value:msgId body:body];
body = [self setParamsKey:@"uid" value:userid body:body];
// 添加分界線,換行
[body appendFormat:@"%@\r\n",MPboundary];
// 聲明文件字段,文件名
[body appendFormat:@"Content-Disposition: form-data; name=\"upfile\"; filename=\"%@\"\r\n",[filedic objectForKey:@"serverfilename"]];
// 聲明上傳文件的格式
[body appendFormat:@"Content-Type: %@\r\n\r\n",[self GetContentType:[filedic objectForKey:@"serverfilename"]]];
// 聲明結(jié)束符:--AaB03x--
NSString *end=[[NSString alloc]initWithFormat:@"\r\n%@",endMPboundary];
// 聲明myRequestData妇萄,用來放入http body
NSMutableData *myRequestData=[NSMutableData data];
// 將body字符串轉(zhuǎn)化為UTF8格式的二進(jìn)制
[myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];
// 將file的data加入
[myRequestData appendData:data];
// 加入結(jié)束符--AaB03x--
[myRequestData appendData:[end dataUsingEncoding:NSUTF8StringEncoding]];
// 設(shè)置HTTPHeader中Content-Type的值
NSString *content=[[NSString alloc]initWithFormat:@"multipart/form-data; boundary=%@",TWITTERFON_FORM_BOUNDARY];
// 設(shè)置HTTPHeader
[request setValue:content forHTTPHeaderField:@"Content-Type"];
// 設(shè)置Content-Length
[request setValue:[NSString stringWithFormat:@"%lu", [myRequestData length]] forHTTPHeaderField:@"Content-Length"];
// 設(shè)置http body
[request setHTTPBody:myRequestData];
// http method
[request setHTTPMethod:@"POST"];
// 開線程下載
dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(defaultQueue, ^{
// 另開線程
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
NSLog(@"上傳狀態(tài)返回值: %@", returnString);
// if ([returnString isEqualToString:@"0"]) {
// [self responseLoadFinish:files msgId:msgId upload:upload];
// } else {
// [self responseLoadFail:files msgId:msgId upload:upload];
// }
});
}
}
+ (NSMutableString*)setParamsKey:(NSString*)key value:(NSString*)value body:(NSMutableString*)body {
NSString *TWITTERFON_FORM_BOUNDARY = @"AaB03x";
// 分界線 --AaB03x
NSString *MPboundary=[[NSString alloc]initWithFormat:@"--%@",TWITTERFON_FORM_BOUNDARY];
// 添加分界線丐重,換行
[body appendFormat:@"%@\r\n",MPboundary];
// 添加字段名稱崖蜜,換2行
[body appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];
// 添加字段的值
[body appendFormat:@"%@\r\n",value];
return body;
}
+ (NSString*)GetContentType:(NSString*)filename {
if ([filename hasSuffix:@".avi"]) {
return @"video/avi";
} else if ([filename hasSuffix:@".bmp"]) {
return @"application/x-bmp";
} else if ([filename hasSuffix:@"jpeg"]) {
return @"image/jpeg";
} else if ([filename hasSuffix:@"jpg"]) {
return @"image/jpeg";
} else if ([filename hasSuffix:@"png"]) {
// chrome/firefox 標(biāo)準(zhǔn)image/png,IE 標(biāo)準(zhǔn)image/x-png
return @"image/png";
} else if ([filename hasSuffix:@"mp3"]) {
return @"audio/mp3";
} else if ([filename hasSuffix:@"mp4"]) {
return @"video/mpeg4";
} else if ([filename hasSuffix:@"rmvb"]) {
return @"application/vnd.rn-realmedia-vbr";
} else if ([filename hasSuffix:@"txt"]) {
return @"text/plain";
} else if ([filename hasSuffix:@"xsl"]) {
return @"application/x-xls";
} else if ([filename hasSuffix:@"xslx"]) {
return @"application/x-xls";
} else if ([filename hasSuffix:@"xwd"]) {
return @"application/x-xwd";
} else if ([filename hasSuffix:@"doc"]) {
return @"application/msword";
} else if ([filename hasSuffix:@"docx"]) {
return @"application/msword";
} else if ([filename hasSuffix:@"ppt"]) {
return @"application/x-ppt";
} else if ([filename hasSuffix:@"pdf"]) {
return @"application/pdf";
}
return nil;
}
@end
原生方式監(jiān)聽網(wǎng)絡(luò)狀態(tài)
方法一 :command + shift + 0打開 Documentation And API reference 搜索 Reachability
方法二:到網(wǎng)頁[下載]https://developer.apple.com/library/content/samplecode/Reachability/Introduction/Intro.html
- 獲取當(dāng)前網(wǎng)絡(luò)狀態(tài)
// [Reachability reachabilityForInternetConnection];只能判斷wifi是否可用,不能判斷是否連接以太網(wǎng)絡(luò)
Reachability *reachability = [Reachability reachabilityWithHostName:@"www.baidu.com"];
NetworkStatus netStatus = [reachability currentReachabilityStatus];
switch (netStatus) {
case NotReachable:
break;
case ReachableViaWiFi:
networkStatus =
break;
case ReachableViaWWAN:
break;
default:
break;
}
- 監(jiān)聽網(wǎng)絡(luò)狀態(tài)
- (void) addNotifacation
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
[self.hostReachability startNotifier];
}
- (void) reachabilityChanged:(NSNotification *)note
{
Reachability* curReach = [note object];
NSParameterAssert([curReach isKindOfClass:[Reachability class]]);
NetworkStatus netStatus = [reachability currentReachabilityStatus];
}
AFNetworking 中封裝的監(jiān)聽網(wǎng)絡(luò)
// 1.獲得網(wǎng)絡(luò)監(jiān)控的管理者
AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];
// 2.設(shè)置網(wǎng)絡(luò)狀態(tài)改變后的處理
[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
// 當(dāng)網(wǎng)絡(luò)狀態(tài)改變了, 就會調(diào)用這個(gè)block
switch(status) {
case AFNetworkReachabilityStatusUnknown: // 未知網(wǎng)絡(luò)
NSLog(@"未知網(wǎng)絡(luò)");
break;
case AFNetworkReachabilityStatusNotReachable: // 沒有網(wǎng)絡(luò)(斷網(wǎng))
NSLog(@"沒有網(wǎng)絡(luò)(斷網(wǎng))");
break;
case AFNetworkReachabilityStatusReachableViaWWAN: // 手機(jī)自帶網(wǎng)絡(luò)
NSLog(@"手機(jī)自帶網(wǎng)絡(luò)");
break;
case AFNetworkReachabilityStatusReachableViaWiFi: // WIFI
NSLog(@"WIFI");
break;
}
}];
// 3.開始監(jiān)控
[mgr startMonitoring];
AFN和ASI有啥不同
1 AFN基于NSURL(NSURLSession&NSURLConnection)襟锐,ASI基于底層的CFNetwork框架,因此ASI的性能優(yōu)于AFN
2 AFN采取block的方式處理請求敲霍,ASI最初采取delegate的方式處理請求艘儒,后面也增加了block的方式
3 AFN只封裝了一些常用功能逾礁,滿足基本需求窒篱,直接忽略了很多擴(kuò)展功能,比如沒有封裝同步請求;ASI提供的功能較多婶溯,預(yù)留了各種接口和工具供開發(fā)者自行擴(kuò)展
4 AFN直接解析服務(wù)器返回的JSON信轿、XML等數(shù)據(jù),而ASI比較原始惠况,返回的是NSData二進(jìn)制數(shù)據(jù)
5 AFN在iOS9.0之后需要網(wǎng)絡(luò)權(quán)限攘蔽,而ASI不需要
在真正的開發(fā)中
如果是普通的GET&POST請求、小文件上傳醉途,強(qiáng)烈建議用AFN,因?yàn)锳FN簡單好用宝惰。
如果是下載強(qiáng)烈建議用ASI拐邪,因?yàn)樗峁┝撕軓?qiáng)大的功能惰赋。
附: