上傳/下載

使用NSURLSession進(jìn)行上傳和下載任務(wù),NSURLSession是iOS7之后推出的,具有downLoadTaskupLoadTask功能沙合,實(shí)現(xiàn)任務(wù)時(shí),會(huì)先將任務(wù)掛起,這樣可以實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能刀荒,使用時(shí)候要注意resume

下載

  • 最簡(jiǎn)單的下載
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1. URL
    NSString *urlString = @"http://192.168.26.201/0805空缺數(shù)據(jù) 2.xls.zip";
    // 添加 % 轉(zhuǎn)義
    urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlString];
    
    // NSURLSession,sharedSession是一個(gè)全局共享的單例,蘋果為了方便程序員使用簡(jiǎn)單的網(wǎng)絡(luò)任務(wù)
//    NSURLSession *session = [NSURLSession sharedSession];
    
    // 2. 由sharedSession發(fā)起網(wǎng)絡(luò)會(huì)話任務(wù)
    [[[NSURLSession sharedSession] downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
        
        NSLog(@"%@", [NSBundle mainBundle].bundlePath);
        NSLog(@"%@", location);
    }] resume];
}
  • 下載解壓縮
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSString *urlString = @"http://192.168.26.201/0805空缺數(shù)據(jù) 2.xls.zip";
    // 添加 % 轉(zhuǎn)義
    urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    NSURL *url = [NSURL URLWithString:urlString];
    
    // NSURLSession,sharedSession是一個(gè)全局共享的單例,蘋果為了方便程序員使用簡(jiǎn)單的網(wǎng)絡(luò)任務(wù)
    NSURLSession *session = [NSURLSession sharedSession];
    
    // 由session發(fā)起下載任務(wù),在URLSession中,所有的任務(wù)都是由session發(fā)起的
    // 下載任務(wù)會(huì)保存在tmp文件夾中,如果沒(méi)有處理,下載的文件會(huì)被刪除!
    /**
     從網(wǎng)絡(luò)上下載小說(shuō)
     
     1. 下載這個(gè)小說(shuō)的zip
     2. 下載完成之后,可以解壓縮,原有的zip包就不需要了
     3. URLSession會(huì)自動(dòng)幫我們刪除這個(gè)zip包
     但是如果調(diào)用了這個(gè)方法不會(huì)調(diào)用相應(yīng)的代理方法,原因不詳,望賜教
     */
    NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
        
        NSLog(@"%@", [NSBundle mainBundle].bundlePath);
        NSLog(@"%@", location);
        
        // 將下載的文件解壓縮到cache目錄 - 重新啟動(dòng)不會(huì)刪除
        NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        
        // 解壓縮 path屬性可以拿到URL中對(duì)應(yīng)的路徑
        //使用了解壓縮框架ZipArchive
        [SSZipArchive unzipFileAtPath:location.path toDestination:cacheDir];
    }];
    
    // 所有的任務(wù),默認(rèn)都是掛起的,需要resume
    [task resume];
}
  • 三個(gè)代理方法

pragma mark - NSURLSession下載代理方法

1.下載完成

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    //這個(gè)操作本身是在異步線程中完成的,如果想要在這個(gè)線程中完成下載解壓操作棘钞,需要在異步線程完成照棋。但是更新UI的操作如collectionView的reloadData要放到主線程去進(jìn)行
    //如果要在這個(gè)方法中使用下載解壓操作,要放到
    NSLog(@"下載完成 %@", location);
}

2.斷點(diǎn)續(xù)傳使用

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
    // 什么也不寫
}

3.下載進(jìn)度

/**
 bytesWritten                   本次下載的字節(jié)數(shù)
 totalBytesWritten              已經(jīng)下載的字節(jié)數(shù)
 totalBytesExpectedToWrite      下載文件總字節(jié)數(shù)
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    // 進(jìn)度 = 已經(jīng)下載 / 總大小
    float progress = (float)totalBytesWritten / totalBytesExpectedToWrite;
    
    NSLog(@"%f %@", progress, [NSThread currentThread]);
    
    // 主線程更新UI GCD
//    dispatch_async(dispatch_get_main_queue(), ^ { self.progressView.progress = progress;});
    // NSOperation
[[NSOperationQueue mainQueue] addOperationWithBlock: ^ { 
        //進(jìn)度條
        self.pView.progress = progress;
    }];
}
  • 斷點(diǎn)續(xù)傳
    主要的是關(guān)于任務(wù)開(kāi)始和釋放
    (注意)

使用下面這個(gè)辦法注冊(cè)NSURLSession對(duì)象時(shí),需要注意到隊(duì)列,可以使用主隊(duì)列,這樣下載任務(wù)只在主隊(duì)列進(jìn)行,使用自己定義的隊(duì)列或者使用nil的時(shí)候,為異步并發(fā)隊(duì)列

+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(id <NSURLSessionDelegate>)delegate delegateQueue:(NSOperationQueue *)queue;

- (NSURLSession *)session
{
    if (_session == nil) {
        NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
        _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    }
    return _session;
}

// 開(kāi)始
- (IBAction)start
{
    self.pView.progress = 0.0f;
    
    // 1. URL
    NSString *urlString = @"http://192.168.26.201/2014蘋果發(fā)布者大會(huì).mp4";
    urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlString];
    
    // 2. session
//    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
//    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    
    // 3. 下載任務(wù)
    self.downloadTask = [self.session downloadTaskWithURL:url];
    [self.downloadTask resume];
}

// 暫停
- (IBAction)pause
{
    // 如果已經(jīng)暫停,應(yīng)該不能再一次暫停
    NSLog(@"%s", __func__);
    
    [self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
        NSLog(@"====> %zd", resumeData.length);
        // 需要把resumeData保存下來(lái),才能保證后續(xù)的續(xù)傳能夠執(zhí)行
        self.resumeData = resumeData;
        
        // 釋放下載任務(wù)!
        self.downloadTask = nil;
    }];
}

// 繼續(xù)
- (IBAction)resume
{
    // 如果已經(jīng)繼續(xù),應(yīng)該不能再次繼續(xù)
    if (self.resumeData == nil) {
        // 說(shuō)明前一次沒(méi)有被暫停的下載任務(wù)
        return;
    }
    
    // 發(fā)起續(xù)傳的網(wǎng)絡(luò)下載任務(wù)
//    [[self.session downloadTaskWithResumeData:self.resumeData] resume];
    self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
    
    // 釋放resumeData
    self.resumeData = nil;
    
    [self.downloadTask resume];
}

  • PUT上傳武翎、刪除文件
@implementation CZViewController
/**
 
 PUT 方法可以上傳任意大小的文件
 
 // 設(shè)置HTTP請(qǐng)求頭屬性
 // ****** 注意:不同的網(wǎng)絡(luò)環(huán)境變化,通常都是設(shè)置HTTP的請(qǐng)求頭字段,通過(guò)請(qǐng)求頭字段可以告訴服務(wù)器很多內(nèi)容!
 // 譬如:上傳文件,授權(quán)信息等等,具體如何設(shè)置,公司的后端程序員會(huì)告訴前端
 
 1. 需要身份驗(yàn)證
 NSString *authStr = @"admin:123456";
 NSString *authBase64 = [@"BASIC " stringByAppendingString:[self base64:authStr]];
 [request setValue:authBase64 forHTTPHeaderField:@"Authorization"];
 
 * DELETE 刪除服務(wù)器上的文件
 
 request.HTTPMethod = @"DELETE";
 
 身份驗(yàn)證和PUT一致!
 */
// PUT上傳
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self putUpload];
}

/** 刪除服務(wù)器上的文件 Web-DAV */
- (void)deleteFile
{
    // 1. URL 中需要指定PUT上傳到服務(wù)器上的文件名
    NSURL *url = [NSURL URLWithString:@"http://192.168.26.201/uploads/123.mp4"];
    
    // 2. request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"DELETE";
    
    // 2.1 設(shè)置用戶名和密碼
    NSString *authStr = @"admin:123456";
    // 結(jié)果: "BASIC YWRtaW46MTIzNDU2"
    NSString *authBase64 = [@"BASIC " stringByAppendingString:[self base64:authStr]];
    // 設(shè)置HTTP請(qǐng)求頭屬性
    // ****** 注意:不同的網(wǎng)絡(luò)環(huán)境變化,通常都是設(shè)置HTTP的請(qǐng)求頭字段,通過(guò)請(qǐng)求頭字段可以告訴服務(wù)器很多內(nèi)容!
    // 譬如:上傳文件,授權(quán)信息等等,具體如何設(shè)置,公司的后端程序員會(huì)告訴前端
    [request setValue:authBase64 forHTTPHeaderField:@"Authorization"];
    
    // 3. sesssion 只能使用request進(jìn)行DELETE刪除
    [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        
        NSLog(@"完成!");
        
    }] resume];
}

- (void)putUpload
{
    // 1. URL 中需要指定PUT上傳到服務(wù)器上的文件名
    NSURL *url = [NSURL URLWithString:@"http://192.168.26.201/uploads/123.png"];
    
    // 2. request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"PUT";
    
    // 2.1 設(shè)置用戶名和密碼
    NSString *authStr = @"admin:123456";
    // 結(jié)果: "BASIC YWRtaW46MTIzNDU2"
    NSString *authBase64 = [@"BASIC " stringByAppendingString:[self base64:authStr]];
    // 設(shè)置HTTP請(qǐng)求頭屬性
    // ****** 注意:不同的網(wǎng)絡(luò)環(huán)境變化,通常都是設(shè)置HTTP的請(qǐng)求頭字段,通過(guò)請(qǐng)求頭字段可以告訴服務(wù)器很多內(nèi)容!
    // 譬如:上傳文件,授權(quán)信息等等,具體如何設(shè)置,公司的后端程序員會(huì)告訴前端
    [request setValue:authBase64 forHTTPHeaderField:@"Authorization"];
    
    // 3. sesssion 只能使用request進(jìn)行PUT上傳
    // 參數(shù)fromFile -> 本地要上傳文件的完成URL
    NSURL *localURL = [[NSBundle mainBundle] URLForResource:@"02.網(wǎng)絡(luò)應(yīng)用層次結(jié)構(gòu).mp4" withExtension:nil];
    
    // 4. 跟蹤上傳進(jìn)度
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
    
    [[session uploadTaskWithRequest:request fromFile:localURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        
        // 提示,跟蹤的時(shí)候一定不要只輸出result
        // 提示:如果是覆蓋文件,NSData沒(méi)有內(nèi)容
        NSLog(@"====> %@", result);
    }] resume];
}

#pragma mark - 上傳文件進(jìn)度代理方法
/**
 bytesSent                  本次上傳字節(jié)數(shù)
 totalBytesSent             總共上傳字節(jié)數(shù)
 totalBytesExpectedToSend   要上傳的字節(jié)數(shù)
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
    float progress = (float)totalBytesSent / totalBytesExpectedToSend;
    
    NSLog(@"%f %@", progress, [NSThread currentThread]);
}

/** 
 將指定的字符串,進(jìn)行base64編碼
 
 BASE64 - 是網(wǎng)絡(luò)上最常用的編碼方式之一(可以編碼->看不懂,可以解碼->又看的懂了)
 
 BASE64是很多加密算法中的基礎(chǔ)算法!
 
 能夠達(dá)到的效果,將二進(jìn)制文件轉(zhuǎn)換成ASCII碼,從而可以將二進(jìn)制文件的結(jié)果直接當(dāng)成URL的參數(shù)傳遞
 */
- (NSString *)base64:(NSString *)string
{
    // 1. 將字符串轉(zhuǎn)換成二進(jìn)制數(shù)據(jù)
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    
    // 2. 進(jìn)行base64編碼
    return [data base64EncodedStringWithOptions:0];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"%@", [self base64:@"admin:123456"]);
}

POST 上傳

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1. URL,是真正負(fù)責(zé)上傳的腳本(php)文件
    NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload.php"];
    
    // 2. request
    /**
     1> 負(fù)責(zé)上傳文件的URL
     2> 上傳的文件名:保存在服務(wù)器上的文件名稱
     3> 本地要上傳文件的完整路徑
     */
    NSString *localPath = [[NSBundle mainBundle] pathForResource:@"001.png" ofType:nil];
    NSURLRequest *request = [NSMutableURLRequest requestWithUploadURL:url uploadFileName:@"123.png" localFilePath:localPath];
    
    // 3. 上傳
    [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@", result);
    }] resume];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末烈炭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子宝恶,更是在濱河造成了極大的恐慌符隙,老刑警劉巖趴捅,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異霹疫,居然都是意外死亡拱绑,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門丽蝎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)猎拨,“玉大人,你說(shuō)我怎么就攤上這事屠阻『焓。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵国觉,是天一觀的道長(zhǎng)吧恃。 經(jīng)常有香客問(wèn)我,道長(zhǎng)麻诀,這世上最難降的妖魔是什么痕寓? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蝇闭,結(jié)果婚禮上呻率,老公的妹妹穿的比我還像新娘。我一直安慰自己呻引,他們只是感情好礼仗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著苞七,像睡著了一般藐守。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蹂风,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天卢厂,我揣著相機(jī)與錄音,去河邊找鬼惠啄。 笑死慎恒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的撵渡。 我是一名探鬼主播融柬,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼趋距!你這毒婦竟也來(lái)了粒氧?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤节腐,失蹤者是張志新(化名)和其女友劉穎外盯,沒(méi)想到半個(gè)月后摘盆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饱苟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年孩擂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箱熬。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡类垦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出城须,到底是詐尸還是另有隱情蚤认,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布酿傍,位于F島的核電站烙懦,受9級(jí)特大地震影響驱入,放射性物質(zhì)發(fā)生泄漏赤炒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一亏较、第九天 我趴在偏房一處隱蔽的房頂上張望莺褒。 院中可真熱鬧,春花似錦雪情、人聲如沸遵岩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)尘执。三九已至,卻和暖如春宴凉,著一層夾襖步出監(jiān)牢的瞬間誊锭,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工弥锄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丧靡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓籽暇,卻偏偏與公主長(zhǎng)得像温治,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子戒悠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容