1.小文件下載
1.1下載方式
- 【NSData dataWithContentsOfURL:】
- [NSURLConntection sendAsynch...]
劣勢:無法下載大文件。原因是無法顯示進度,用戶體驗很差;再有一口氣下載完給內存,內存會爆的。
2.大文件下載
2.1 NSURLConnection基本下載
NSURL * **url =
NSURLRequest *request =
//下載(創建萬conn對象后,會自動發起一個異步請求)
【NSURLConnection connectionWithRequest:requeset delegate:self】
這里面的代理就是監聽下載進度的
有四個代理方法
//比如請求失敗(請求超時,網絡異常)
- (void)connection:(NSURLConnection *)connection didFailWithError:()error{}
//接收到服務器的響應就會調用
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
if(self.currentLength) return;
//取出文件的總長度
//NSHTTPURLResponse *resp = (NSHTTPURLRespone *)response;
//long long fileLength = [resp.allHeaderFields[@"Content--Length"]longlongValuse];
self.totalLength = response.expectedContentLength
//文件路徑
NSString *cache = NSSearchPathForDir.....
NSString *filePath = [cache stringByAppendingPath...];
//創建一個空的文件到沙盒中
NSFileManager *mgr = [NSFileManager defaultManager];
[mgr createFileAtPath:filePath contents:nil attributes:nil];
//創建一個用來寫數據的文件句柄,用來關聯文件
self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
}
//當接收到服務器返回的實體數據時調用
- (void)connection:(NSURLConnection *)connection didReceiveDate:(NSData *)data{
static int total = 0;
self.currentLength +=data.length
[self.fileData appendData:data];
self.progressView.progress = (double)self.currentLength /self.totalLength
//移動到文件的最后面
[self.writeHandle seekToEndOfFile];
//寫入數組
[self.wtiteHandle writeData:data];
}
//服務器的數據已經完全返回
- (void)connectionDidFinshLoading:(NSURLConnection *)connection {
[self.writeHandle closeFile];
self.WtriteHandle = nil;
}
要知道兩個:總大小,現在下到那個地方了。總大小在響應頭里面,有響應的大小和類型。
//寫到沙盒中去,文件太大的話不要寫到Document中,要是太大會被據。想要保存又不備份的話存到Library中的Caches中去;NSURLConnection的異步一個為block一個為代理
那么要是網絡出問題,怎么從斷點出接著下載,用按鈕模擬。按鈕的話狀態取反就可以了。
- download:(UIButton *)sender{
sender.selected = !sender.isSelected;
if(sender.selected){//繼續(開始)下載
NSURL *url =
NSMutableURLRequest *request = [NSMutableURLRequest requestWIthURl:url];
//設置請求頭
NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
[request setValue:range forHttpHeaderFidle:@"Range"];
//下載(創建萬conn對象后,會自動發起一個異步請求)
self.conn = 【NSURLConnection connectionWithRequest:requeset delegate:self】
}else{//暫停
[self.coon cancel];
}
}
2.2多線程斷點下載
思路 :這個就要用到一開始就要在沙盒中創建一個一樣大小的文件,里面是01的二進制.之后根據range的來分為幾個線程。每個線程下載的部分存入到沙盒中的固定位置。
2.3 NSURLSession
2.3.1基本掌握
相對來說,從post、get請求上沒有比NSURLConnection精簡多少,比較出眾的地方在文件下載.當我們下載文件時,它的內部是直接存儲到沙盒中的temp文件中,所以我們要對文件進行處理,要不會別刪掉。把文件剪切到Library中的Caches文件中。是iOS7退出來替代NSURLConnection。
**
任務:任何請求都是一個任務
NSURLSessionDataTask:普通的get、post請求
NSURLSessionDownloadTask:文件的下載
優點:邊下載變緩存到沙盒的temp文件中,而且方便斷點續傳。
NSURLSessionUploadTask:文件的上傳
**
- (void)touchesBegan:{
}
//下載進度2
- (void)download2{
//
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration defaultSessionConfiguration];
//得到session對象
NSURLSession *session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSQperationQueue mainQueue]];
//創建一個下載task
NSURL *url = [NSURL urlWithString:@"http:..."];
NSURLSessionDownloadTask *task = [session downloadWithTaskWithURL:url ];
//要是handle這個block的話,優先執行block,不會執行協議
//開始任務
[task resume];
}
//代理的方法
//下載完后的路徑
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
//將臨時文件剪切或者復制到Caches文件夾
NSString *cachs = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];
//:response.suggestedFilename:建議使用的文件名,一般跟服務器端的文件名一樣
NSString *file = [caches stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
//將臨時文件剪切或者復制Caches文件夾
NSFileMagnger *age = [NSFileManger defaultManger];
[mgr moveItemAtPath:location.path toPath:file error:nil];
}
/ **第一個參數:bytesWritten 這次調用寫了多少
totalBytesWritten 累計寫入多少長度到沙盒中
totalBytesExpectedToWrite 文件的總長度
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)byteWtitten totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
double progress = (double )totalBytesWritten /totalBytesExpectedToWrite ;
}
//下載任務:不能看到下載進度
- (void)download{
//得到一個session對象
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL urlWithString:@"http:..."];
NSURLSessionDownloadTask *task = [session downloadWithTaskWithURL:url completionHandle:^(NSURL*location,NSURLRespone *respone ,NSError *error)]{
//location:臨時文件的路徑(下載好的文件)
//將臨時文件剪切或者復制到Caches文件夾
NSString *cachs = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];
//:response.suggestedFilename:建議使用的文件名,一般跟服務器端的文件名一樣
NSString *file = [caches stringByAppendingPathComponent:response.suggestedFilename];
//將臨時文件剪切或者復制Caches文件夾
NSFileMagnger *age = [NSFileManger defaultManger];
[mgr moveItemAtPath:location.path toPath:file error:nil];
}];
//開始任務
[task resume];
}
- (void)dataTask{
//得到一個session對象
NSURLSession *session = [NSURLSession sharedSession];
//創建一個task任務
NSURL *url = [NSURL urlWithString:@"http:..."];
//創建一個請求 ,這是一個post請求,get的話差不多
NSMurableURLRequest *request =[NSMurableURLRequest requestWithURL:url];
reuqest.HTTPMethod = @"POST";
//設置請求體,先不加密了。轉為請求提Data
request.HTTPBody = [@"username=123&pwd=123" dataUseingEncoding:NSUTF8StringEncoding];
//在這里存入到沙盒中的temp文件夾中
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandle:^(NSData *data,NSURLRespone *respone ,NSError *error)]{
//假設服務器返回的是字典
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData :data options :NSJSONReadingMutableLeaves error:nil];
NSFileMagnger *age = [NSFileManger defaultManger];
NSSearchPathDicteciory * = []
}
}
2.3.2斷點下載
- download:(UIButton *)sender{
//按鈕狀態取反
sender.selected = !sender.isSelected;
if(self.task == nil){//繼續(開始)下載
if(self.resumeData){
[self.resumeData];//恢復
}else {
[self start];//開始
}
}else{//暫停
[selfcancel];
}
}
- (void)start{
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration defaultSessionConfiguration];
//得到session對象
NSURLSession *session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSQperationQueue mainQueue]];
//創建一個下載task
NSURL *url = [NSURL urlWithString:@"http:..."];
self*task = [session downloadWithTaskWithURL:url ];
//開始任務
[self.task resume];
}
- (void)resume{
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration defaultSessionConfiguration];
//得到session對象, 這里面的隊列是存放代理方法和block,這樣的話我們獲取數據的就是為了刷新UI,還有方法調用太頻繁,這樣我們就放入到主線程里面。
NSURLSession *session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSQperationQueue mainQueue]];
//傳入上次暫停下載返回的數據,就可以恢復下載
self.task = [self.session downloadTaskWithResumeData:self.resumeData];
//開始任務
[self.task resume];
//清空
self.resumeData = nil;
}
- (void)pause{
//self引用了task,而task又用了block,里面又點上了屬性,所以要weak下
__weak typeof(self )vc = self;
[self.task cancelByProducingResumeData:^(NSData *resumeData){
//resumeData :包含了繼續下載的開始位置和下載的URL
vc.resumeData = resumeData;
vc.task = nil;
}];
}
//協議方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
//將臨時文件剪切或者復制到Caches文件夾
NSString *cachs = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];
//:response.suggestedFilename:建議使用的文件名,一般跟服務器端的文件名一樣
NSString *file = [caches stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
//將臨時文件剪切或者復制Caches文件夾
NSFileMagnger *age = [NSFileManger defaultManger];
[mgr moveItemAtPath:location.path toPath:file error:nil];
}
3.文件上傳
文件上傳要首先服務器要有這個功能,
用HTTP的post就可以達到文件上傳,像是圖片,音樂,視頻,文件等。
4.AFN
4.1基本使用(下載)
AFN是基于NSURLConnection和NSURLSession,之后才是CFNetwork,而ASI基于CFNetwork所以效率上時ASI快些。
AFHTTPRequestOperationManager是AFN中最重要的對象之一,封裝了HTTP請求的常見處理GET\POST請求,解析服務器的響應數據。
二大管理對象
AFHTTPRequestOperationManager:對NSURLCOnnection的封裝
AFHTPSessionManager:對NSURLSession的封裝
AFHTTPRequestOperationManager的具體使用
1.創建管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
2.封裝請求參數
//請求參數,用可變字典就是代碼規范
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
3.發送請求
這個是在異步線程中,不用我們再調回主線程中。
[[NSOperationQueue mainQueue] addOperation:任務];
- [ mgr GET:url parameters:params
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{
}
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{
}
并且AFN對服務器返回的數據進行解析,默認為JSON來解析。我們也可以自己設置解析方式,像是XML和NSData。
//選擇序列化器
mgr.responseSerializer = [AFXMLParserResponseSerializer serializer];
*** 服務器返回的數據一定要跟respoSerializer對的上**
- (void)teachesBegan...{
}
- (void)getPost{
//創建
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//默認為JSON
mgr.responseSerializer = [AFJSONParserResponseSerializer serializer];
//請求參數,用可變字典就是代碼規范
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
NSString *url @"http:///..";
//GET請求 并且params 里面是中文的話AFN也會轉碼,responseObject也是字典不是NSData,也不用我們去轉換格式,那么想把二進制轉為字符串,添加一個分類Foundation+log分類
- [ mgr POST:url parameters:params
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{
}
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{
}
}
//這個就無法轉為字典了
- (void)XML{
//創建
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//選擇序列化器
mgr.responseSerializer = [AFXMLParserResponseSerializer serializer];
//請求參數,用可變字典就是代碼規范
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
pparams[@"type"] = @"XML";
NSString *url @"http:///..";
//GET請求 并且params 里面是中文的話AFN也會轉碼,responseObject也是字典不是NSData,也不用我們去轉換格式,那么想把二進制轉為字符串,添加一個分類Foundation+log分類
- [ mgr GET:url parameters:params
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{
}
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{
}
}
}
//想下載的數據比如圖片和文件不像轉為JSON或者是XML,就是NSData
- (void)getData{
//創建
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//默認為JSON
mgr.responseSerializer = [AFHTTPResponseSerializer serializer];
//請求參數,用可變字典就是代碼規范
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
NSString *url @"http:///..";
//GET請求 并且params 里面是中文的話AFN也會轉碼,responseObject也是字典不是NSData,也不用我們去轉換格式,那么想把二進制轉為字符串,添加一個分類Foundation+log分類
[ mgr GET:url parameters:params
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{
//要是XML數據,想要解析那么
NSXMLParser *parser = [NSXMLParser alloc] initWithData :responseObject];
}
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{
}
}
//AFHTTPRequestOperationManager是對NSURLConnection的封裝
- (void)getJSON{
//創建
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//默認為JSON
mgr.responseSerializer = [AFJSONParserResponseSerializer serializer];
//請求參數,用可變字典就是代碼規范
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
NSString *url @"http:///..";
//GET請求 并且params 里面是中文的話AFN也會轉碼,responseObject也是字典不是NSData,也不用我們去轉換格式,那么想把二進制轉為字符串,添加一個分類Foundation+log分類
[ mgr GET:url parameters:params
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{
}
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{
}]
}
4.2文件上傳
文件上傳
AFN不支持文件上傳進度查看,ASI支持。而文件較大時,斷點續傳的技術一般的HTTP服務器都不支持,常用的技術用的是Socket(TCP\IP)
- (void)teachesBegan:(NSSet *)ouches withEvent:(UIEvent *)event{
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle :@"選擇圖片" delegate:self cncelButtonTitl:@"cancel" destructiveButtonTitle:nil otherButtonTitles:@"拍照",@"相冊"];
[sheet showInView:self.view.window];
** 寫的時候出了一個錯,就是當莫打出一個控制器的時候,sheet還沒有銷毀,但是卻無法show in 控制器上就出錯了,所以添加到window上,這樣view不在窗口上的話也沒有事情 **
}
//UIActionSheet 代理方法
- (void)actionSheet :(UIActionSheet *)actionSheet cickedButtonAtIndex:(NSInteger)buttonIndex{
//switch語法在里面定義變量的話要有
//上傳手機的圖片給服務器,上傳來源:拍照 相冊
UIImagePickerController *ipc = [[UIImagePickerController alloc ]init];
//設置代理
ipc.delegate = self;
switch (butonIndex){
case 0 :{
if(![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) return;
//設置圖片的來源
ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
break;
}
case 1:{
if(![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhoto]) return;
//設置圖片的來源
ipc.sourceType = UIImagePickerControllerSourceTypePhoto;
break;
}
}
[self presentiewController:ipc animated:YES completion:nil];
}
//UIImagePickerController 代理方法
//info 里面包含了圖片信息
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
//銷毀控制器
[picker dismissViewCOntrollerAnimated:YES completion:nil];
//獲得圖片
UIImage *image = info[UIImagePickerControllerOriginalImage];
}
- (void)upload{
//創建一個管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//封裝參數,這里放非文件參數
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
NSString *url @"http:///..";
[ mgr POST:url parameters:params constructingBodyWithBlock:^(id<AFMultipatrFormData> formData){
//在發送請求之前會自動調用這個block,在這里添加文件參數到formData中
/**
FileURL:需要上傳的文件的URL路徑
name:服務器那邊接收文件用的參數名
fileName :(告訴服務器)所長傳文件的文件名
mimeType:所上傳文件的文件類型
[formData appendPartWithFileURL :url name :@"" fileName : mimeType: error: ];
*/
//FileData:所上傳的文件的具體數據
UIImage *image = [UIImage imageNamed:@"min_01"];
NSData *fileData = UIImagePNGRepresentation(image);
[formData appendPartWithFileData :fileData name :@"file" fileName :@"haha.png" mimeType:@"image/png" error: nil];
} success:^(AFHTTPRequestOperation *operation, id responseObject)success{
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)failure{
}];
}
4.3監聽網絡狀態
蘋果原生的非常麻煩,AFN自己封裝了一個
- (void)viewDidLoad{
AFNetworkReachabilitManager *mgr = [AFNetworkReachabilitManager sharedManager];
[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilitManager status){
//當前網絡狀態發生改變的時候調用這個block
switc(status){
case AFNetworkReachabilityStatusReachableViaFi; break;
case AFNetworkReachabilityStatusReachableWWAN; break;
case AFNetworkReachabilityStatusNotReachable; break;
}
}]
//開始監控
[mgr startMonitoring];
}
- (void)dealloc{
[[AFNetworkReachabilitManager sharedManager] stopMonitoring];
}