2.1 URLRequest 的設置
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video"]];
// 設置緩存策略
/*
// 默認的緩存策略,會在本地緩存
NSURLRequestUseProtocolCachePolicy = 0,
// 忽略本地緩存數據,永遠都是從服務器獲取數據,不使用緩存,應用場景:股票,彩票
NSURLRequestReloadIgnoringLocalCacheData = 1,
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData
// 首先使用緩存,若是沒有本地緩存,才從原地址下載
NSURLRequestReturnCacheDataElseLoad = 2,
// 使用本地緩存,從不下載,若是本地沒有緩存,則請求失敗和 "離線" 數據訪問有關,能夠和 Reachability 框架結合使用,
// 若是用戶聯網,直接使用默認策略。若是沒有聯網,可使用返回緩存策略,鄭重提示:要把用戶拉到網絡上來。
NSURLRequestReturnCacheDataDontLoad = 3,
// 無視任何緩存策略,不管是本地的仍是遠程的,老是從原地址從新下載
NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented
// 若是本地緩存是有效的則不下載,其餘任何狀況都從原地址從新下載
NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented
緩存的數據保存在沙盒路徑下 Caches 文件夾中的 SQLite 數據庫中。
*/
urlRequest.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
// 設置超時時間
urlRequest.timeoutInterval = 120;
// 設置請求模式
/*
默認是 GET
*/
urlRequest.HTTPMethod = @"POST";
// 設置請求體
urlRequest.HTTPBody = [@"type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
// 設置請求頭
/*
告訴服務器客戶端類型,只能寫英文,User-Agent 是固定的 key
*/
[urlRequest setValue:@"iPhone 6s Plus" forHTTPHeaderField:@"User-Agent"];
2.2 URLSessionConfiguration 的設置
- 在開發一款應用程序的時候,一般只會訪問一臺服務器,若是全部的設置在 session 中統一設置一次,後續的網絡訪問方法,會很是簡單,一次設置,全局有效。
- 在 URLSession 中,會使用 config 替代不少原有 request 中的附加設置。config 用於設置全局的網絡會話屬性,
- 包括:瀏覽器類型,Content-Type,身份驗證,Cookie,超時時長,緩存策略,
- 主機最大鏈接數...。NSURLSessionConfiguration 擁有 20 個屬性。熟練掌握這些屬性的用處,將使應用程序充分利用其網絡環境。
- 經常使用屬性:
HTTPAdditionalHeaders HTTP 請求頭,告訴服務器有關客戶端的附加信息,這對於跨會話共享信息,
如內容類型,語言,用戶代理,身份認證,是頗有用的。
Accept 告訴服務器客戶端可接收的數據類型,如:@"application/json" 。
Accept-Language 告訴服務器客戶端使用的語言類型,如:@"en" 。
Authorization 驗證身份信息,如:authString 。
User-Agent 告訴服務器客戶端類型,如:@"iPhone AppleWebKit" 。
range 用於斷點續傳,如:bytes=10- 。
networkServiceType 網絡服務類型,對標準的網絡流量,網絡電話,語音,視頻,以及由一個後臺進程使用的流量
進行了區分。大多數應用程序都不須要設置這個。
NSURLNetworkServiceTypeDefault 默認
NSURLNetworkServiceTypeVoIP VoIP
NSURLNetworkServiceTypeVideo 視頻
NSURLNetworkServiceTypeBackground 後臺
NSURLNetworkServiceTypeVoice 語音
allowsCellularAccess 容許蜂窩訪問,和 discretionary 自行決定,被用於節省經過蜂窩鏈接的帶寬。
建議在使用後臺傳輸的時候,使用 discretionary 屬性,而不是 allowsCellularAccess
屬性,由於它會把 WiFi 和電源可用性考慮在內。
timeoutIntervalForRequest 超時時長,許多開發人員試圖使用 timeoutInterval 去限制發送請求的總時間,但這誤會了
timeoutIntervalForRequest 的意思:報文之間的時間。
timeoutIntervalForResource 整個資源請求時長,實際上提供了總體超時的特性,這應該只用於後臺傳輸,而不是用戶實際上
可能想要等待的任何東西。
HTTPMaximumConnectionsPerHost 對於一個 host 的最大併發鏈接數,iOS 默認數值是 4,MAC 下的默認數值是 6,從某種程度上,
替代了 NSOpeartionQueue 的最大併發線程數。是 Foundation 框架中 URL 加載系統的一個新
的配置選項。它曾經被用於 NSURLConnection 管理私人鏈接池。如今有了 NSURLSession,開發
者能夠在須要時限制鏈接到特定主機的數量。平常開發中,幾乎不用去管 session 的最大併發數。
HTTPShouldUsePipelining 也出如今 NSMutableURLRequest,它能夠被用於開啓 HTTP 管道,這能夠顯着下降請求的加載時
間,可是因爲沒有被服務器普遍支持,默認是禁用的。
sessionSendsLaunchEvents 是另外一個新的屬性,該屬性指定該會話是否應該從後臺啓動。
connectionProxyDictionary 指定了會話鏈接中的代理服務器。一樣地,大多數面向消費者的應用程序都不須要代理,因此基本上不
須要配置這個屬性。關於鏈接代理的更多信息能夠在 CFProxySupport Reference 找到。
Cookie Policies
HTTPCookieStorage 被會話使用的 cookie 存儲。默認狀況下,NSHTTPCookieShorage 的 sharedHTTPCookieStorage
會被使用,這與 NSURLConnection 是相同的。
HTTPCookieAcceptPolicy 決定了該會話應該接受從服務器發出的 cookie 的條件。
HTTPShouldSetCookies 指定了請求是否應該使用會話 HTTPCookieStorage 的 cookie。
Security Policies
URLCredentialStorage 會話使用的證書存儲。默認狀況下,NSURLCredentialStorage 的sharedCredentialStorage 會被
使用,這與 NSURLConnection 是相同的。
TLSMaximumSupportedProtocol 肯定是否支持 SSLProtocol 版本的會話。
TLSMinimumSupportedProtocol 肯定是否支持 SSLProtocol 版本的會話。
Caching Policies
URLCache 會話使用的緩存。默認狀況下,NSURLCache 的sharedURLCache 會被使用,這與 NSURLConnection
是相同的。
requestCachePolicy 緩存策略,指定一個請求的緩存響應應該在何時返回。這至關於 NSURLRequest 的 cachePolicy
方法。
Custom Protocols
protocolClasses 註冊 NSURLProtocol 類的特定會話數組。
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
// 設置同時鏈接到一臺服務器的最大鏈接數
configuration.HTTPMaximumConnectionsPerHost = 4;
// 設置受權信息,WebDav 的身份驗證
NSString *username = @"admin";
NSString *password = @"adminpasswd";
NSString *userPasswordString = [NSString stringWithFormat:@"%@:%@", username, password];
NSData *userPasswordData = [userPasswordString dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64EncodedCredential = [userPasswordData base64EncodedStringWithOptions:0];
NSString *authString = [NSString stringWithFormat:@"Basic: %@", base64EncodedCredential];
// 設置客戶端類型
NSString *userAgentString = @"iPhone AppleWebKit";
// 設置請求頭
configuration.HTTPAdditionalHeaders = @{@"Accept": @"application/json",
@"Accept-Language": @"en",
@"Authorization": authString,
@"User-Agent": userAgentString};
2.2 URLSession 建立方式
Important
The session object keeps a strong reference to the delegate until your app explicitly invalidates the session.
If you do not invalidate the session by calling the invalidateAndCancel or resetWithCompletionHandler: method,
your app leaks memory.
一旦指定了 session 的代理,session 會對代理進行強引用,若是不主動取消 session,會形成內存泄漏。
釋放強引用的辦法:
1> 網絡操做完成:
取消 session 標記:
session 完成而且無效,已經被取消的會話,沒法再次使用。
__weak typeof(self) weakSelf = self;
[weakSelf.session finishTasksAndInvalidate];
釋放 session:
__weak typeof(self) weakSelf = self;
weakSelf.session = nil;
優勢:可以保證下載任務的正常完成。
壞處:每一次網絡訪問結束後,都要銷燬 session,會形成 session 的重複建立和銷燬。
2> 視圖控制器銷燬以前,將 session 釋放掉:
viewWillDisappear 方法中,將 session 銷燬
[self.session invalidateAndCancel];
self.session = nil;
好處:只會在視圖控制器被銷燬以前,纔會釋放 session,避免重複的建立和銷燬。
缺點:session 被取消後,下載任務一樣會被取消(有些版本的 Xcode)。
3> 關於網絡訪問,一般都是創建一個網路訪問的單例:
若是單例的工具類,自己就是 session 的代理,單例會隨着引用程序被銷燬,纔會被釋放。就不須要考慮 session 的釋放問題。
// 共享會話方式
/*
爲了方便程序員使用,蘋果提供了一個全局 session,全局 session 的回調是異步的,全部的任務都是由 session 發起的。要跟進下
載進度,不能使用全局 session。
該會話使用全局的 Cache,Cookie 和證書。
*/
NSURLSession *urlSession1 = [NSURLSession sharedSession];
// 配置會話方式
/*
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
configuration:
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
NS_AVAILABLE(10_10, 8_0)
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier;
默認會話模式(default):工做模式相似於原來的 NSURLConnection,使用的是基於磁盤緩存的持久化策略,使用用戶鑰匙串中保
存的證書進行認證受權。
瞬時會話模式(ephemeral):該模式不使用磁盤保存任何數據。全部和會話相關的緩存,證書,cookies 等都被保存在 RAM 中,
所以當程序使會話無效,這些緩存的數據就會被自動清空。這對於實現像 "祕密瀏覽" 功能的功能來講,是很理想的。
後臺會話模式(background):該模式在後臺完成上傳和下載,後臺會話不一樣於常規的普通的會話,它甚至能夠在應用程序掛起,退
出,崩潰的狀況下運行上傳和下載任務。初始化時指定的標識符,被用於向任何可能在進程外恢復後臺傳輸的守護進程提供上下文。想要查
看更多關於後臺會話的信息,能夠查看WWDC Session 204: 「What’s New with Multitasking」。
*/
NSURLSession *urlSession2 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
// 配置會話協議方式
/*
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
delegate:(nullable id <NSURLSessionDelegate>)delegate
delegateQueue:(nullable NSOperationQueue *)queue;
queue:
注意:下載自己的線程 "只有一條",代理回調能夠在 "多個線程" 回調,指定代理執行的隊列,不會影響到下載自己的執行。
如何選擇隊列:網絡訪問結束後,若是不須要作複雜的操做,能夠指定主隊列,這樣不用考慮線程間通信
主隊列回調:
[NSOperationQueue mainQueue]
代理方法在主線程中調用。
下載自己是異步執行的,這一點和 NSURLConnection 同樣。
NSURLSession 即便在主線程回調也不會形成阻塞。
異步回調:
[[NSOperationQueue alloc] init]
nil
代理方法在子線程中調用。
二三兩種方式能夠建立一個新會話並定製其會話類型。該方式中指定了 session 的委託和委託所處的隊列。當再也不須要鏈接時,能夠調用
Session 的 invalidateAndCancel 直接關閉,或者調用 finishTasksAndInvalidate 等待當前 Task 結束後關閉。這時 Delegate
會收到 URLSession:didBecomeInvalidWithError: 這個事件。Delegate 收到這個事件以後會被解引用。
*/
NSURLSession *urlSession3 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
2.3 Task 建立方式
// 數據請求 NSURLSessionDataTask (GET/POST)
// 數據請求 request block 方式
NSURLSessionDataTask *urlSessionDataTask1 = [urlSession1 dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// block 在子線程中執行
}];
// 數據請求 request 協議 方式
// 遵照協議 <NSURLSessionDataDelegate>
NSURLSessionDataTask *urlSessionDataTask2 = [urlSession3 dataTaskWithRequest:urlRequest];
// 數據請求 url block 方式
/*
1)該方法內部會自動將請求路徑包裝成一個請求對象,該請求對象默認包含了請求頭信息和請求方法(GET)
2)若是要發送的是 POST 請求,則不能使用該方法。
*/
NSURLSessionDataTask *urlSessionDataTask3 = [urlSession1 dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// block 在子線程中執行
}];
// 數據請求 url 協議 方式
/*
1)該方法內部會自動將請求路徑包裝成一個請求對象,該請求對象默認包含了請求頭信息和請求方法(GET)
2)若是要發送的是 POST 請求,則不能使用該方法。
*/
// 遵照協議 <NSURLSessionDataDelegate>
NSURLSessionDataTask *urlSessionDataTask4 = [urlSession3 dataTaskWithURL:url];
// 文件下載 NSURLSessionDownloadTask
// 文件下載 request block 方式
NSURLSessionDownloadTask *urlSessionDownloadTask1 = [urlSession1 downloadTaskWithRequest:urlRequest completionHandler:^(NSURL * _Nullable location,NSURLResponse * _Nullable response, NSError * _Nullable error) {
// block 在子線程中執行
// location 是下載的文件臨時存儲路徑,下載完成後會被自動刪除
}];
// 文件下載 request 協議 方式
// 遵照協議 <NSURLSessionDownloadDelegate>
NSURLSessionDownloadTask *urlSessionDownloadTask2 = [urlSession3 downloadTaskWithRequest:urlRequest];
// 文件下載 url block 方式
NSURLSessionDownloadTask *urlSessionDownloadTask3 = [urlSession1 downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// block 在子線程中執行
// location 是下載的文件臨時存儲路徑,下載完成後會被自動刪除
}];
// 文件下載 url 協議 方式
// 遵照協議 <NSURLSessionDownloadDelegate>
NSURLSessionDownloadTask *urlSessionDownloadTask4 = [urlSession3 downloadTaskWithURL:url];
// 文件下載 resumeData block 方式
NSData *resumeData = nil;
NSURLSessionDownloadTask *urlSessionDownloadTask5 = [urlSession1 downloadTaskWithResumeData:resumeData completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// block 在子線程中執行
// 斷點續傳,resumeData 爲以前已經下載的數據
// location 是下載的文件臨時存儲路徑,下載完成後會被自動刪除
}];
// 文件下載 resumeData 協議 方式
// 遵照協議 <NSURLSessionDownloadDelegate>
NSURLSessionDownloadTask *urlSessionDownloadTask6 = [urlSession3 downloadTaskWithResumeData:resumeData];
// 文件上傳 NSURLSessionUploadTask
// 文件上傳 fromFile block 方式
NSURL *uploadFileUrl = nil;
NSURLSessionUploadTask *urlSessionUploadTask1 = [urlSession1 uploadTaskWithRequest:urlRequest fromFile:uploadFileUrl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// block 在子線程中執行
}];
// 文件上傳 fromFile 協議 方式
// 遵照協議 <NSURLSessionDataDelegate>
NSURLSessionUploadTask *urlSessionUploadTask2 = [urlSession3 uploadTaskWithRequest:urlRequest fromFile:uploadFileUrl];
// 文件上傳 fromData block 方式
NSData *uploadFileData = nil;
NSURLSessionUploadTask *urlSessionUploadTask3 = [urlSession1 uploadTaskWithRequest:urlRequest fromData:uploadFileData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// block 在子線程中執行
}];
// 文件上傳 fromData 協議 方式
// 遵照協議 <NSURLSessionDataDelegate>
NSURLSessionUploadTask *urlSessionUploadTask4 = [urlSession3 uploadTaskWithRequest:urlRequest fromData:uploadFileData];
// 文件上傳 Streamed Request 方式
NSURLSessionUploadTask *urlSessionUploadTask5 = [urlSession1 uploadTaskWithStreamedRequest:urlRequest];
// 開始 Task 任務
[urlSessionDownloadTask1 resume];
// 暫停 Task 任務
[urlSessionDownloadTask1 suspend];
// 取消 Task 任務
// 徹底取消,下次下載又從 0.0% 開始
[urlSessionDownloadTask1 cancel];
// 可恢復性取消,下次下載可從 保存的 resumeData 處開始
[urlSessionDownloadTask1 cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
}];
// location 是下載的文件臨時存儲路徑,下載完成後會被自動刪除。response.suggestedFilename 爲服務器端文件名。
NSString *documentsDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:response.suggestedFilename];
// 設置下載的文件存儲路徑
/*
處理下載的數據
*/
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:documentsDirPath error:nil];
2.6 文件上傳設置
#define boundary @"myBoundary"
// 設置請求頭
/*
upload task 不會在請求頭裏添加 content-type (上傳數據類型)字段,@"myBoundary" 爲請求體邊界,參數能夠隨便設置,但需一致
*/
[urlRequest setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] forHTTPHeaderField:@"Content-Type"];
// 設置請求文件參數
NSMutableData *fromBody = [NSMutableData data];
// 參數開始分割線
/*
每一個參數開始前都須要加
*/
[fromBody appendData:[[NSString stringWithFormat:@"--%@", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[fromBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// 參數
[fromBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@", @"username", @"jhq"] dataUsingEncoding:NSUTF8StringEncoding]];
[fromBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// 文件開始分割線
/*
每一個文件開始前都須要加
*/
[fromBody appendData:[[NSString stringWithFormat:@"--%@", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[fromBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// 文件參數名
/*
test.png 爲上傳後服務器端文件名稱
*/
[fromBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"", @"file", @"test.png"] dataUsingEncoding:NSUTF8StringEncoding]];
[fromBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// 文件的類型
[fromBody appendData:[[NSString stringWithFormat:@"Content-Type: image/png"] dataUsingEncoding:NSUTF8StringEncoding]];
[fromBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[fromBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// 待上傳文件數據
/*
本地待上傳的文件路徑
*/
[fromBody appendData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"HQ_0005" ofType:@"jpg"]]];
[fromBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// 結束分割線標記
[fromBody appendData:[[NSString stringWithFormat:@"--%@--", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[fromBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
3.1 使用 request block 回調方式
// 設置請求路徑
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=JSON"];
// 建立請求對象
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 建立會話對象
NSURLSession *urlSession = [NSURLSession sharedSession];
// 發送請求
NSURLSessionDataTask *urlSessionDataTask = [urlSession dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 處理從服務器下載的數據
if (error == nil && data != nil) {
}
}];
// 執行任務
[urlSessionDataTask resume];
3.2 使用 request 協議 方式
// 遵照協議 <NSURLSessionDataDelegate>
@property(nonatomic, retain)NSMutableData *asyncNetData;
// 設置請求路徑
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=JSON"];
// 建立請求對象
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 建立會話對象
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self
delegateQueue:[[NSOperationQueue alloc] init]];
// 發送請求
NSURLSessionDataTask *urlSessionDataTask = [urlSession dataTaskWithRequest:urlRequest];
// 執行任務
[urlSessionDataTask resume];
// 協議方法
// 接收到服務器的響應
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
/*
須要使用 completionHandler 回調告訴系統應該如何處理服務器返回的數據,默認是取消的。
NSURLSessionResponseCancel = 0, 默認的處理方式,取消
NSURLSessionResponseAllow = 1, 接收服務器返回的數據
NSURLSessionResponseBecomeDownload = 2, 變成一個下載請求
NSURLSessionResponseBecomeStream 變成一個流
*/
// 接收服務器返回的數據
completionHandler(NSURLSessionResponseAllow);
// 異步下載數據源初始化
self.asyncNetData = [[NSMutableData alloc] init];
}
// 接收到服務器數據
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
// 拼接從服務器下載的數據
[self.asyncNetData appendData:data];
}
// 服務器的數據加載完畢
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (error == nil) {
// 處理從服務器下載的數據
id result = [NSJSONSerialization JSONObjectWithData:self.asyncNetData options:0 error:NULL];
NSLog(@"異步 GET 網絡請求完成: \n%@", result);
}
}
3.3 使用 url block 回調方式
// 設置請求路徑
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=JSON"];
// 建立會話對象
NSURLSession *urlSession = [NSURLSession sharedSession];
// 發送請求
NSURLSessionDataTask *urlSessionDataTask = [urlSession dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 處理從服務器下載的數據
if (error == nil && data != nil) {
}
}];
// 執行任務
[urlSessionDataTask resume];
3.4 使用 url 協議 方式
// 遵照協議 <NSURLSessionDataDelegate>
@property(nonatomic, retain)NSMutableData *asyncNetData;
// 設置請求路徑
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=JSON"];
// 建立會話對象
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self
delegateQueue:[[NSOperationQueue alloc] init]];
// 發送請求
NSURLSessionDataTask *urlSessionDataTask = [urlSession dataTaskWithURL:url];
// 執行任務
[urlSessionDataTask resume];
// 協議方法
// 接收到服務器的響應
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
/*
須要使用 completionHandler 回調告訴系統應該如何處理服務器返回的數據,默認是取消的。
NSURLSessionResponseCancel = 0, 默認的處理方式,取消
NSURLSessionResponseAllow = 1, 接收服務器返回的數據
NSURLSessionResponseBecomeDownload = 2, 變成一個下載請求
NSURLSessionResponseBecomeStream 變成一個流
*/
// 接收服務器返回的數據
completionHandler(NSURLSessionResponseAllow);
// 異步下載數據源初始化
self.asyncNetData = [[NSMutableData alloc] init];
}
// 接收到服務器數據
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
// 拼接從服務器下載的數據
[self.asyncNetData appendData:data];
}
// 服務器的數據加載完畢
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (error == nil) {
// 處理從服務器下載的數據
id result = [NSJSONSerialization JSONObjectWithData:self.asyncNetData options:0 error:NULL];
NSLog(@"異步 GET 網絡請求完成: \n%@", result);
}
}
5.1 使用 request block 回調方式
// 設置請求路徑
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_01.mp4"];
// 建立請求對象
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 建立會話對象
NSURLSession *urlSession = [NSURLSession sharedSession];
NSURLSessionDownloadTask *urlSessionDownloadTask = [urlSession downloadTaskWithRequest:urlRequest completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error == nil) {
// 設置下載的文件存儲路徑
NSString *documentsDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:response.suggestedFilename];
// 處理下載的數據
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:documentsDirPath error:nil];
}
}];
// 執行任務
[urlSessionDownloadTask resume];
5.2 使用 request 協議 方式
// 遵照協議 <NSURLSessionDownloadDelegate>
// 設置請求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
// 建立請求對象
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 建立會話對象
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
// 發送請求
NSURLSessionDownloadTask *urlSessionDownloadTask = [urlSession downloadTaskWithRequest:urlRequest];
// 執行任務
[urlSessionDownloadTask resume];
// 協議方法
// 監聽下載進度,每當寫入數據到臨時文件時,就會調用一次這個方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
// 此次寫入多少
NSLog(@"bytesWritten: %lli", bytesWritten);
// 已經寫入的大小
NSLog(@"totalBytesWritten: %lli", totalBytesWritten);
// 總大小
NSLog(@"totalBytesExpectedToWrite: %lli", totalBytesExpectedToWrite);
float progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
dispatch_async(dispatch_get_main_queue(), ^{
// 設置下載進度條
self.progressView.progress = progress;
});
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
// 設置下載的文件存儲路徑
NSString *documentsDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
// 處理下載的數據
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:documentsDirPath error:nil];
}
// 恢復下載任務時調用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {
}
// 下載完成或中斷
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
}
5.3 使用 url block 回調方式
// 設置請求路徑
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_01.mp4"];
// 建立會話對象
NSURLSession *urlSession = [NSURLSession sharedSession];
NSURLSessionDownloadTask *urlSessionDownloadTask = [urlSession downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error == nil) {
// 設置下載的文件存儲路徑
NSString *documentsDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:response.suggestedFilename];
// 處理下載的數據
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:documentsDirPath error:nil];
}
}];
// 執行任務
[urlSessionDownloadTask resume];
5.4 使用 url 協議 方式
// 遵照協議 <NSURLSessionDownloadDelegate>
// 設置請求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
// 建立會話對象
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 發送請求
NSURLSessionDownloadTask *urlSessionDownloadTask = [urlSession downloadTaskWithURL:url];
// 執行任務
[urlSessionDownloadTask resume];
// 協議方法
// 監聽下載進度,每當寫入數據到臨時文件時,就會調用一次這個方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
// 此次寫入多少
NSLog(@"bytesWritten: %lli", bytesWritten);
// 已經寫入的大小
NSLog(@"totalBytesWritten: %lli", totalBytesWritten);
// 總大小
NSLog(@"totalBytesExpectedToWrite: %lli", totalBytesExpectedToWrite);
float progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
dispatch_async(dispatch_get_main_queue(), ^{
// 設置下載進度條
self.progressView.progress = progress;
});
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
// 設置下載的文件存儲路徑
NSString *documentsDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
// 處理下載的數據
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:documentsDirPath error:nil];
}
// 恢復下載任務時調用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {
}
// 下載完成或中斷
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
}
5.5 斷點續傳下載方式
// 開始下載
_downloadSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:
_resumeTmpPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"resumeData.tmp"];
if ([[NSFileManager defaultManager] fileExistsAtPath:self.resumeTmpPath] == NO) {
// 屢次中止下載,下載的臨時文件 會 被自動刪除
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
self.downloadTask = [self.downloadSession downloadTaskWithURL:url];
// 從新開始下載
[self.downloadTask resume];
} else {
self.resumeData = [NSData dataWithContentsOfFile:self.resumeTmpPath];
// 使用斷點下載須要以前下載的臨時文件存在,才能繼續下載
self.downloadTask = [self.downloadSession downloadTaskWithResumeData:self.resumeData];
// 斷點開始下載
[self.downloadTask resume];
}
// 暫停下載
[self.downloadTask suspend];
// 繼續下載
[self.downloadTask resume];
// 中止下載
// 中止下載。一旦這個 task 被取消了,就沒法再恢復
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
if (resumeData) {
self.resumeData = resumeData;
[self.resumeData writeToFile:self.resumeTmpPath atomically:YES];
}
self.downloadTask = nil;
}];
// 協議方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
float progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
dispatch_async(dispatch_get_main_queue(), ^{
[self.progressBtn q_setButtonWithProgress:progress lineWidth:10 lineColor:nil backgroundColor:[UIColor yellowColor]];
});
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
// 處理下載的數據
NSString *documentsDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:documentsDirPath error:NULL];
// 刪除斷點下載緩存文件
[[NSFileManager defaultManager] removeItemAtPath:self.resumeTmpPath error:NULL];
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {
NSLog(@"恢復下載,已完成:%f%%", (100.0 * fileOffset / expectedTotalBytes));
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(@"didCompleteWithError --- 中斷下載: %@", error.userInfo[NSLocalizedDescriptionKey]);
if (error) {
// 獲取斷點數據
self.resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
}
// 下載的臨時文件不存在時
if ([error.localizedFailureReason isEqualToString:@"No such file or directory"]) {
// 刪除斷點下載緩存文件,不然繼續斷點下載會報錯
[[NSFileManager defaultManager] removeItemAtPath:self.resumeTmpPath error:nil];
[self start];
}
}
5.6 後臺下載方式
// 配置爲後臺下載方式
NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"myBackgroundID"];
_downloadSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]];
[[self.downloadSession downloadTaskWithRequest:request] resume];
// 協議方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
float progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
dispatch_async(dispatch_get_main_queue(), ^{
[self.progressBtn q_setButtonWithProgress:progress lineWidth:10 lineColor:nil backgroundColor:[UIColor yellowColor]];
});
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSString *documentsDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]
stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
[[NSFileManager defaultManager] moveItemAtPath:location.path toPath:documentsDirPath error:nil];
}
-
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://192.168.88.200/upload/upload.php"]];
urlRequest.HTTPMethod = @"POST";
#define boundary @"uploadBoundary"
// 設置請求頭
[urlRequest setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] forHTTPHeaderField:@"Content-Type"];
// 設置請求文件參數
NSMutableData *formData = [NSMutableData data];
// 參數
[formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n",@"username"] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[[NSString stringWithFormat:@"\r\n%@\r\n", @"qian"] dataUsingEncoding:NSUTF8StringEncoding]];
// 文件
[formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", @"userfile", @"test1.jpg"] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[[NSString stringWithFormat:@"Content-Type: image/jpeg\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"HQ_0005" ofType:@"jpg"]]];
[formData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// 結束
[formData appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSession *urlSession = [NSURLSession sharedSession];
NSURLSessionUploadTask *urlSessionUploadTask = [urlSession uploadTaskWithRequest:urlRequest fromData:formData completionHandler:^(NSData * _Nullable data,NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
[urlSessionUploadTask resume];
-
// 遵照協議 <NSURLSessionDataDelegate>
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://192.168.88.200/upload/upload.php"]];
urlRequest.HTTPMethod = @"POST";
#define boundary @"uploadBoundary"
// 設置請求頭
[urlRequest setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] forHTTPHeaderField:@"Content-Type"];
// 設置請求文件參數
NSMutableData *formData = [NSMutableData data];
// 參數
[formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n",@"username"] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[[NSString stringWithFormat:@"\r\n%@\r\n", @"qian"] dataUsingEncoding:NSUTF8StringEncoding]];
// 文件
[formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", @"userfile", @"test2.png"] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[[NSString stringWithFormat:@"Content-Type: image/png\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[formData appendData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"HQ_0011" ofType:@"png"]]];
[formData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// 結束
[formData appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
NSURLSessionUploadTask *urlSessionUploadTask = [urlSession uploadTaskWithRequest:urlRequest fromData:formData];
[urlSessionUploadTask resume];
// 協議方法
// 監聽上傳進度
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
float progress = 1.0 * totalBytesSent / totalBytesExpectedToSend;
dispatch_async(dispatch_get_main_queue(), ^{
[self.progressBtn q_setButtonWithProgress:progress lineWidth:10 lineColor:nil backgroundColor:[UIColor yellowColor]];
});
}
// 接收到服務器的響應
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
/*
須要使用 completionHandler 回調告訴系統應該如何處理服務器返回的數據,默認是取消的。
NSURLSessionResponseCancel = 0, 默認的處理方式,取消
NSURLSessionResponseAllow = 1, 接收服務器返回的數據
NSURLSessionResponseBecomeDownload = 2, 變成一個下載請求
NSURLSessionResponseBecomeStream 變成一個流
*/
completionHandler(NSURLSessionResponseAllow);
// 異步下載數據源初始化
self.asyncNetData = [[NSMutableData alloc] init];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
[self.asyncNetData appendData:data];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
}
-
- 文件數據封裝使用到第三方框架 QExtension,具體實現代碼見 GitHub 源碼 QExtension
#import "NSData+FormData.h"
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://192.168.88.200/upload/upload.php"]];
urlRequest.HTTPMethod = @"POST";
NSURL *fileURL = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"HQ_0011" ofType:@"png"]];
NSData *formData = [NSData q_formDataWithRequest:urlRequest text:@"qian" textName:@"username" fileURL:fileURL name:@"userfile" fileName:nil mimeType:nil];
[[[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest fromData:formData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}] resume];
-
- 文件數據封裝使用到第三方框架 QExtension,具體實現代碼見 GitHub 源碼 QExtension
#import "NSData+FormData.h"
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://192.168.88.200/upload/upload-m.php"]];
urlRequest.HTTPMethod = @"POST";
NSURL *fileURL1 = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"HQ_0005" ofType:@"jpg"]];
NSURL *fileURL2 = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"HQ_0011" ofType:@"png"]];
NSData *formData = [NSData q_formDataWithRequest:urlRequest texts:@[@"qian"] textNames:@[@"username"] fileURLs:@[fileURL1, fileURL2] name:@"userfile[]"fileNames:nil mimeTypes:nil];
[[[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest fromData:formData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}] resume];
6.5 PUT Block 方式
// NSString+Base64.m
@implementation NSString (Base64)
- (NSString *)q_base64Encode {
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
return [data base64EncodedStringWithOptions:0];
}
- (NSString *)q_basic64AuthEncode {
return [@"BASIC " stringByAppendingString:[self q_base64Encode]];
}
@end
// ViewController.m
// 本地要上傳的文件
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"minion.mp4" withExtension:nil];
// 123.mp4 保存到服務器的文件名
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/uploads/123.mp4"];
// PUT 文件上傳,以文件的方式直接寫入到 WebDav 服務器中
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
urlRequest.HTTPMethod = @"PUT";
// 服務器驗證,用戶訪問名和密碼
[urlRequest setValue:[@"admin:adminpasswd" q_basic64AuthEncode] forHTTPHeaderField:@"Authorization"];
[[[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest fromFile:fileURL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}] resume];
6.6 PUT 協議 方式
// NSString+Base64.m
@implementation NSString (Base64)
- (NSString *)q_base64Encode {
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
return [data base64EncodedStringWithOptions:0];
}
- (NSString *)q_basic64AuthEncode {
return [@"BASIC " stringByAppendingString:[self q_base64Encode]];
}
@end
// ViewController.m
// 遵照協議 <NSURLSessionDataDelegate>
// 本地要上傳的文件
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"minion.mp4" withExtension:nil];
// 123.mp4 保存到服務器的文件名
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/uploads/123.mp4"];
// PUT 文件上傳,以文件的方式直接寫入到 WebDav 服務器中
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
urlRequest.HTTPMethod = @"PUT";
// 服務器驗證,用戶訪問名和密碼
[urlRequest setValue:[@"admin:adminpasswd" q_basic64AuthEncode] forHTTPHeaderField:@"Authorization"];
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
[[urlSession uploadTaskWithRequest:urlRequest fromFile:fileURL] resume];
// 協議方法
// 監聽上傳進度
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
float progress = 1.0 * totalBytesSent / totalBytesExpectedToSend;
dispatch_async(dispatch_get_main_queue(), ^{
[self.progressBtn q_setButtonWithProgress:progress lineWidth:10 lineColor:nil backgroundColor:[UIColor yellowColor]];
});
}
// 接收到服務器的響應
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
/*
須要使用 completionHandler 回調告訴系統應該如何處理服務器返回的數據,默認是取消的。
NSURLSessionResponseCancel = 0, 默認的處理方式,取消
NSURLSessionResponseAllow = 1, 接收服務器返回的數據
NSURLSessionResponseBecomeDownload = 2, 變成一個下載請求
NSURLSessionResponseBecomeStream 變成一個流
*/
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
}