iOS網(wǎng)絡(luò)基礎(chǔ)——NSURLSession使用詳解(一般訪問(wèn)策肝、文件下載、上傳)

一隐绵、整體介紹

  • NSURLSession在2013年隨著iOS7的發(fā)布一起面世之众,蘋(píng)果對(duì)它的定位是作為NSURLConnection的替代者,然后逐步將NSURLConnection退出歷史舞臺(tái)∫佬恚現(xiàn)在使用最廣泛的第三方網(wǎng)絡(luò)框架:AFNetworking棺禾、SDWebImage等等都使用了NSURLSession。作為iOS開(kāi)發(fā)人員峭跳,應(yīng)該緊隨蘋(píng)果的步伐膘婶,不斷的學(xué)習(xí),無(wú)論是軟件的更新蛀醉、系統(tǒng)的更新悬襟、API的更新,而不能墨守成規(guī)拯刁。

  • Session翻譯為中文意思是會(huì)話(huà)脊岳,我們知道,在七層網(wǎng)絡(luò)協(xié)議中有物理層->數(shù)據(jù)鏈路層->網(wǎng)絡(luò)層->傳輸層->會(huì)話(huà)層->表示層->應(yīng)用層筛璧,那我們可以將NSURLSession類(lèi)理解為會(huì)話(huà)層逸绎,用于管理網(wǎng)絡(luò)接口的創(chuàng)建、維護(hù)夭谤、刪除等等工作,我們要做的工作也只是會(huì)話(huà)層之后的層即可巫糙,底層的工作NSURLSession已經(jīng)幫我們封裝好了朗儒。

    OSI參考模型
  • 另外還有一些Session,比如AVAudioSession用于音視頻訪問(wèn)参淹,WCSession用于WatchOS通訊醉锄,它們都是建立一個(gè)會(huì)話(huà),并管理會(huì)話(huà)浙值,封裝一些底層恳不,方便我們使用。舉一反三开呐。

二烟勋、使用的一般步驟

其核心就是對(duì)網(wǎng)絡(luò)任務(wù)進(jìn)行封裝规求,實(shí)現(xiàn)多線(xiàn)程。比如將一個(gè)網(wǎng)絡(luò)請(qǐng)求交給NSURLSession卵惦,最后NSURLSession將訪問(wèn)結(jié)果通過(guò)block回調(diào)返回阻肿,期間自動(dòng)實(shí)現(xiàn)多線(xiàn)程,而且可以通過(guò)代理實(shí)現(xiàn)監(jiān)聽(tīng)(是否成功沮尿,當(dāng)前的進(jìn)度等等)丛塌; 大致分為3個(gè)步驟:

1 NSURL:請(qǐng)求地址,定義一個(gè)網(wǎng)絡(luò)資源路徑:

NSURL *url = [NSURL URLWithString:@"協(xié)議://主機(jī)地址/路徑?參數(shù)&參數(shù)"];

解釋如下:

  • 協(xié)議:不同的協(xié)議畜疾,代表著不同的資源查找方式赴邻、資源傳輸方式,比如常用的http啡捶,ftp等
  • 主機(jī)地址:存放資源的主機(jī)的IP地址(域名)
  • 路徑:資源在主機(jī)中的具體位置
  • 參數(shù):參數(shù)可有可無(wú)姥敛,也可以多個(gè)。如果帶參數(shù)的話(huà)届慈,用“?”號(hào)后面接參數(shù)徒溪,多個(gè)參數(shù)的話(huà)之間用&隔開(kāi)

2 NSURLRequest:請(qǐng)求,根據(jù)前面的NSURL建立一個(gè)請(qǐng)求:

NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0];

參數(shù)解釋如下:

  • url:資源路徑
  • cachePolicy:緩存策略(無(wú)論使用哪種緩存策略金顿,都會(huì)在本地緩存數(shù)據(jù))臊泌,類(lèi)型為美劇類(lèi)型,取值如下:
    • NSURLRequestUseProtocolCachePolicy = 0 //默認(rèn)的緩存策略揍拆,使用協(xié)議的緩存策略
    • NSURLRequestReloadIgnoringLocalCacheData = 1 //每次都從網(wǎng)絡(luò)加載
    • NSURLRequestReturnCacheDataElseLoad = 2 //返回緩存否則加載渠概,很少使用
    • NSURLRequestReturnCacheDataDontLoad = 3 //只返回緩存,沒(méi)有也不加載嫂拴,很少使用
  • timeoutInterval:超時(shí)時(shí)長(zhǎng)播揪,默認(rèn)60s

另外,還可以設(shè)置其它一些信息筒狠,比如請(qǐng)求頭猪狈,請(qǐng)求體等等,如下:

注意辩恼,下面的request應(yīng)為NSMutableURLRequest雇庙,即可變類(lèi)型

// 告訴服務(wù)器數(shù)據(jù)為json類(lèi)型
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 
// 設(shè)置請(qǐng)求體(json類(lèi)型)
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:@{@"userid":@"123456"} options:NSJSONWritingPrettyPrinted error:nil];
request.HTTPBody = jsonData; 

3 NSURLSession:創(chuàng)建NSURLSession發(fā)送請(qǐng)求

  • 為了方便使用,蘋(píng)果提供了一個(gè)全局的NSURLSession單例灶伊,如同NSURLConnection一樣疆前。這樣做的缺陷就是不能監(jiān)控,如果想要監(jiān)控每一個(gè)請(qǐng)求聘萨,則必須通過(guò)代理來(lái)監(jiān)聽(tīng)竹椒,我們知道單例是一對(duì)多的,而代理是一對(duì)一米辐,因此必須自己實(shí)例化單獨(dú)的Session任務(wù)對(duì)象(NSURLConnection則很難)胸完,來(lái)實(shí)現(xiàn)單獨(dú)監(jiān)控书释。
  • 系統(tǒng)一共提供了5種任務(wù)類(lèi),繼承關(guān)系如下圖所示舶吗。其中NSURLSessionTask為抽象類(lèi)征冷,不能實(shí)現(xiàn)網(wǎng)絡(luò)訪問(wèn),NSURLSessionStreanTask(以流的方式進(jìn)行網(wǎng)絡(luò)訪問(wèn))使用的比較少.使用的多的是dataTask誓琼、downloadTask检激、uploadTask,即圖中紅色框框圈的部分腹侣,基本滿(mǎn)足了網(wǎng)絡(luò)訪問(wèn)的基本需求:獲取數(shù)據(jù)(通常是JSON叔收、XML等)、文件上傳傲隶、文件下載饺律。這三個(gè)類(lèi)都是NSURLSessionTask這個(gè)抽象類(lèi)的子類(lèi),相比直接使用NSURLConnection,NSURLSessionTask支持任務(wù)的暫停跺株、取消和恢復(fù)复濒,并且默認(rèn)任務(wù)運(yùn)行在其他非主線(xiàn)程中。
  • 根據(jù)圖中代理協(xié)議的名字不難發(fā)現(xiàn)乒省,每一個(gè)任務(wù)類(lèi)都有相對(duì)應(yīng)的代理協(xié)議巧颈,只有NSURLSessionUploadTask沒(méi)有對(duì)應(yīng)的代理協(xié)議,因?yàn)镹SURLSessionUploadTask繼承自NSURLSessionDataTask袖扛,因此NSURLSessionDataDelegate即為NSURLSessionUploadTask對(duì)應(yīng)的代理協(xié)議砸泛。
類(lèi)繼承關(guān)系

代理協(xié)議類(lèi)繼承關(guān)系

三 舉例

1.NSURLSession請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)

下面以蘋(píng)果提供的全局NSURLSession單例為例,代碼如下:

/// 向網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)
- (void)NSURLSessionTest {
    // 1.創(chuàng)建url
    // 請(qǐng)求一個(gè)網(wǎng)頁(yè)
    NSString *urlString = @"http://www.baidu.com";
    // 一些特殊字符編碼
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *url = [NSURL URLWithString:urlString];
    
    // 2.創(chuàng)建請(qǐng)求 并:設(shè)置緩存策略為每次都從網(wǎng)絡(luò)加載 超時(shí)時(shí)間30秒
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:30];

    // 3.采用蘋(píng)果提供的共享session
    NSURLSession *sharedSession = [NSURLSession sharedSession];
    
    // 4.由系統(tǒng)直接返回一個(gè)dataTask任務(wù)
    NSURLSessionDataTask *dataTask = [sharedSession dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // 網(wǎng)絡(luò)請(qǐng)求完成之后就會(huì)執(zhí)行蛆封,NSURLSession自動(dòng)實(shí)現(xiàn)多線(xiàn)程
        NSLog(@"%@",[NSThread currentThread]);
        if (data && (error == nil)) {
            // 網(wǎng)絡(luò)訪問(wèn)成功
            NSLog(@"data=%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        } else {
            // 網(wǎng)絡(luò)訪問(wèn)失敗
            NSLog(@"error=%@",error);
        }
    }];
    
    // 5.每一個(gè)任務(wù)默認(rèn)都是掛起的唇礁,需要調(diào)用 resume 方法
    [dataTask resume];
}

2.NSURLSession文件下載

/// 文件下載
- (void)NSURLSessionDownloadTaskTest {
    // 1.創(chuàng)建url
    NSString *urlString = [NSString stringWithFormat:@"http://localhost/周杰倫 - 楓.mp3"];
    // 一些特殊字符編碼
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *url = [NSURL URLWithString:urlString];
    
    // 2.創(chuàng)建請(qǐng)求
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    // 3.創(chuàng)建會(huì)話(huà),采用蘋(píng)果提供全局的共享session
    NSURLSession *sharedSession = [NSURLSession sharedSession];
    
    // 4.創(chuàng)建任務(wù)
    NSURLSessionDownloadTask *downloadTask = [sharedSession downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error == nil) {
            // location:下載任務(wù)完成之后,文件存儲(chǔ)的位置惨篱,這個(gè)路徑默認(rèn)是在tmp文件夾下!
            // 只會(huì)臨時(shí)保存盏筐,因此需要將其另存
            NSLog(@"location:%@",location.path);
            
            // 采用模擬器測(cè)試,為了方便將其下載到Mac桌面
//            NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
            NSString *filePath = @"/Users/coohua/Desktop/周杰倫 - 楓.mp3";
            NSError *fileError;
            [[NSFileManager defaultManager] copyItemAtPath:location.path toPath:filePath error:&fileError];
            if (fileError == nil) {
                NSLog(@"file save success");
            } else {
                NSLog(@"file save error: %@",fileError);
            }
        } else {
            NSLog(@"download error:%@",error);
        }
    }];
    
    // 5.開(kāi)啟任務(wù)
    [downloadTask resume];
}

3.NSURLSession文件上傳

3.1 采用uploadTask任務(wù)砸讳,以數(shù)據(jù)流的方式進(jìn)行上傳
這種方式好處就是大小不受限制机断,上傳需要服務(wù)器端腳本支持,腳本源代碼見(jiàn)本文最后的附錄绣夺,客戶(hù)端示例代碼如下:

/// 以流的方式上傳,大小理論上不受限制欢揖,但應(yīng)注意時(shí)間
- (void) NSURLSessionBinaryUploadTaskTest {
    // 1.創(chuàng)建url  采用Apache本地服務(wù)器
    NSString *urlString = @"http://localhost/upload.php";
    //    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
    NSURL *url = [NSURL URLWithString:urlString];
    
    // 2.創(chuàng)建請(qǐng)求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 文件上傳使用post
    request.HTTPMethod = @"POST";
    
    // 3.開(kāi)始上傳   request的body data將被忽略陶耍,而由fromData提供
    [[[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:[NSData dataWithContentsOfFile:@"/Users/coohua/Desktop/IMG_0359.jpg"]     completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error == nil) {
            NSLog(@"upload success:%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        } else {
            NSLog(@"upload error:%@",error);
        }
    }] resume];
}

3.2 采用dataTask任務(wù),拼接表單的方式進(jìn)行上傳

  • 上傳的關(guān)鍵是請(qǐng)求體部分的表單拼接她混,獲取本地上傳文件的類(lèi)型(MIME Types)烈钞,至于具體的網(wǎng)絡(luò)上傳則很簡(jiǎn)單泊碑。 另外拼接表單的方式會(huì)有大小限制,即HTML的MAX_FILE_SIZE限制(可以自己設(shè)定毯欣,一般2MB)馒过。

  • 根據(jù)上面的繼承關(guān)系圖,我們知道uploadTask是dataTask的子類(lèi)酗钞,也可以使用uploadTask來(lái)代替dataTask腹忽。在代碼示例中4.2步驟完全可以替換4.1步驟。這時(shí)砚作,uploadTaskWithRequest函數(shù)的fromData可有可無(wú)窘奏,文件已在request里面包含。

注意:然而在蘋(píng)果官方對(duì)uploadTaskWithRequest函數(shù)的介紹:request的body data in this request object are ignored葫录,會(huì)被忽略着裹,而測(cè)試時(shí)發(fā)現(xiàn)沒(méi)有被忽略,且request必須包含HTTPBody米同,反而fromData被忽略骇扇。那么暫時(shí)理解為蘋(píng)果對(duì)uploadTaskWithRequest函數(shù)的使用時(shí)沒(méi)有考慮拼接表單的方式,那么當(dāng)我們使用拼接表單時(shí)面粮,建議不要使用uploadTask少孝,雖然這樣也能成功

  • 服務(wù)器端用到的upload.php源代碼見(jiàn)本文最后的附錄

表單拼接格式如下,boundary作為分界線(xiàn):

--boundary
Content-Disposition:form-data;name=”表單控件名稱(chēng)”;filename=”上傳文件名稱(chēng)”
Content-Type:要上傳文件MIME Types

要上傳文件二進(jìn)制數(shù)據(jù);

--boundary--

拼接表單示例代碼:

/// 文件上傳
- (void)NSURLSessionUploadTaskTest {
    // 1.創(chuàng)建url  采用Apache本地服務(wù)器
    NSString *urlString = @"http://localhost/upload/upload.php";
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
    NSURL *url = [NSURL URLWithString:urlString];
    
    // 2.創(chuàng)建請(qǐng)求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 文件上傳使用post
    request.HTTPMethod = @"POST";
    
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",@"boundary"];
    
    [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
    // IMG_0359.jpg
    // 3.拼接表單但金,大小受MAX_FILE_SIZE限制(2MB)  FilePath:要上傳的本地文件路徑  formName:表單控件名稱(chēng)韭山,應(yīng)于服務(wù)器一致
    NSData* data = [self getHttpBodyWithFilePath:@"/Users/coohua/Desktop/IMG_0359.jpg" formName:@"file" reName:@"newName.png"];
    request.HTTPBody = data;
    // 根據(jù)需要是否提供,非必須,如果不提供冷溃,session會(huì)自動(dòng)計(jì)算
    [request setValue:[NSString stringWithFormat:@"%lu",data.length] forHTTPHeaderField:@"Content-Length"];

    // 4.1 使用dataTask
    [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error == nil) {
            NSLog(@"upload success:%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        } else {
            NSLog(@"upload error:%@",error);
        }
        
    }] resume];
#if 0
    // 4.2 開(kāi)始上傳 使用uploadTask   fromData:可有可無(wú)钱磅,會(huì)被忽略
    [[[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:nil     completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error == nil) {
            NSLog(@"upload success:%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        } else {
            NSLog(@"upload error:%@",error);
        }
    }] resume];
#endif
}

/// filePath:要上傳的文件路徑   formName:表單控件名稱(chēng)  reName:上傳后文件名
- (NSData *)getHttpBodyWithFilePath:(NSString *)filePath formName:(NSString *)formName reName:(NSString *)reName
{
    NSMutableData *data = [NSMutableData data];
    NSURLResponse *response = [self getLocalFileResponse:filePath];
    // 文件類(lèi)型:MIMEType  文件的大小:expectedContentLength  文件名字:suggestedFilename
    NSString *fileType = response.MIMEType;
    
    // 如果沒(méi)有傳入上傳后文件名稱(chēng),采用本地文件名!
    if (reName == nil) {
        reName = response.suggestedFilename;
    }
    
    // 表單拼接
    NSMutableString *headerStrM =[NSMutableString string];
    [headerStrM appendFormat:@"--%@\r\n",@"boundary"];
    // name:表單控件名稱(chēng)  filename:上傳文件名
    [headerStrM appendFormat:@"Content-Disposition: form-data; name=%@; filename=%@\r\n",formName,reName];
    [headerStrM appendFormat:@"Content-Type: %@\r\n\r\n",fileType];
    [data appendData:[headerStrM dataUsingEncoding:NSUTF8StringEncoding]];
    
    // 文件內(nèi)容
    NSData *fileData = [NSData dataWithContentsOfFile:filePath];
    [data appendData:fileData];
    
    NSMutableString *footerStrM = [NSMutableString stringWithFormat:@"\r\n--%@--\r\n",@"boundary"];
    [data appendData:[footerStrM  dataUsingEncoding:NSUTF8StringEncoding]];
//    NSLog(@"dataStr=%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    return data;
}
/// 獲取響應(yīng)似枕,主要是文件類(lèi)型和文件名
- (NSURLResponse *)getLocalFileResponse:(NSString *)urlString
{
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
    // 本地文件請(qǐng)求
    NSURL *url = [NSURL fileURLWithPath:urlString];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    __block NSURLResponse *localResponse = nil;
    // 使用信號(hào)量實(shí)現(xiàn)NSURLSession同步請(qǐng)求
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        localResponse = response;
        dispatch_semaphore_signal(semaphore);
    }] resume];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    return  localResponse;
}

四 NSURLSessionConfiguration

NSURLConnection是全局性的盖淡,即它的配置對(duì)全局有效,如果有兩個(gè)鏈接需要不同的cookies凿歼、證書(shū)這些公共資源褪迟,則NSURLConnection無(wú)法滿(mǎn)足要求,這時(shí)NSURLSession的優(yōu)勢(shì)則體現(xiàn)出來(lái)答憔,NSURLSession可以同過(guò)NSURLSessionConfiguration可以設(shè)置全局的網(wǎng)絡(luò)訪問(wèn)屬性味赃。

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
// delegateQueue:請(qǐng)求完成回調(diào)函數(shù)和代理函數(shù)的運(yùn)行線(xiàn)程,如果為nil則系統(tǒng)自動(dòng)創(chuàng)建一個(gè)串行隊(duì)列虐拓,不影響sessionTask的運(yùn)行線(xiàn)程
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];

三種會(huì)話(huà)方式:

  1. defaultSessionConfiguration:進(jìn)程內(nèi)會(huì)話(huà)(默認(rèn)會(huì)話(huà))心俗,類(lèi)似 NSURLConnection的標(biāo)準(zhǔn)配置,用硬盤(pán)來(lái)緩存數(shù)據(jù)。
  2. ephemeralSessionConfiguration:臨時(shí)的進(jìn)程內(nèi)會(huì)話(huà)(內(nèi)存)城榛,不會(huì)將cookie揪利、緩存儲(chǔ)存到本地,只會(huì)放到內(nèi)存中狠持,當(dāng)應(yīng)用程序退出后數(shù)據(jù)也會(huì)消失,可以用于實(shí)現(xiàn)“秘密瀏覽”
  3. backgroundSessionConfiguration:建立后臺(tái)會(huì)話(huà)可以在應(yīng)用程序掛起疟位,退出,崩潰的情況下運(yùn)行上傳和下載任務(wù)喘垂,后臺(tái)另起一個(gè)線(xiàn)程甜刻。另外,系統(tǒng)會(huì)根據(jù)設(shè)備的負(fù)載程度決定分配下載的資源王污,因此有可能會(huì)很慢甚至超時(shí)失敗罢吃。

設(shè)置一些網(wǎng)絡(luò)屬性:

  • HTTPAdditionalHeaders:可以設(shè)置出站請(qǐng)求的數(shù)據(jù)頭
configuration.HTTPAdditionalHeaders = @{
    @"Accept": @"application/json",  
    @"Accept-Language": @"en",
    @"Authorization": authString,
    @"User-Agent": userAgentString
};
  • networkServiceType,設(shè)置網(wǎng)絡(luò)服務(wù)類(lèi)型
    • NSURLNetworkServiceTypeDefault 默認(rèn)
    • NSURLNetworkServiceTypeVoIP VoIP
    • NSURLNetworkServiceTypeVideo 視頻
    • NSURLNetworkServiceTypeBackground 后臺(tái)
    • NSURLNetworkServiceTypeVoice 語(yǔ)音
  • allowsCellularAccess:允許蜂窩訪問(wèn)
  • timeoutIntervalForRequest:請(qǐng)求的超時(shí)時(shí)長(zhǎng)
  • requestCachePolicy:緩存策略

注意事項(xiàng):如果是自定義會(huì)話(huà)并指定了代理昭齐,會(huì)話(huà)會(huì)對(duì)代理進(jìn)行強(qiáng)引用,在視圖控制器銷(xiāo)毀之前尿招,需要取消網(wǎng)絡(luò)會(huì)話(huà),否則會(huì)造成內(nèi)存泄漏

附錄——服務(wù)器端文件上傳PHP源代碼

  • 以表單形式上傳阱驾,可以獲取文件名等等信息就谜,注意images文件夾的權(quán)限應(yīng)為所有用戶(hù)可讀寫(xiě):
<?php
    header("Content-type: application/json; charset=utf-8");
    // 配置文件需要上傳到服務(wù)器的路徑,需要允許所有用戶(hù)有可寫(xiě)權(quán)限里覆,否則無(wú)法上傳丧荐!
    $uploaddir = 'images/';
    // file表單名稱(chēng),應(yīng)與客戶(hù)端一致
    $uploadfile = $uploaddir . basename($_FILES['file']['name']);
    
    move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile);
    
    echo json_encode($_FILES);
?>
  • 以文件流的形式上傳文件喧枷,文件的名字沒(méi)有動(dòng)態(tài)獲取虹统,而是直接命名,注意images文件夾的權(quán)限應(yīng)為所有用戶(hù)可讀寫(xiě)
<?php
    /** 二進(jìn)制流生成文件
     * $_POST 無(wú)法解釋二進(jìn)制流隧甚,需要用到 $GLOBALS['HTTP_RAW_POST_DATA'] 或 php://input
     * $GLOBALS['HTTP_RAW_POST_DATA'] 和 php://input 都不能用于 enctype=multipart/form-data
     * @param    String  $file   要生成的文件路徑
     * @return   boolean
     */
    function binary_to_file($file){
        $content = $GLOBALS['HTTP_RAW_POST_DATA'];          // 需要php.ini設(shè)置
        if(empty($content)){
            $content = file_get_contents('php://input');    // 不需要php.ini設(shè)置车荔,內(nèi)存壓力小
        }
        $ret = file_put_contents($file, $content, true);
        return $ret;
    }
    $file_dir="images/image.png";  // 固定的文件名,注意設(shè)置images文件夾權(quán)限為所有用戶(hù)可讀寫(xiě)!F莅狻忧便!
    binary_to_file($file_dir);
?>

關(guān)于NSURLSession還有很多,后續(xù)會(huì)再貼一些例子 未完待續(xù)帽借。珠增。。

GitHub示例代碼下載

參考:http://www.cnblogs.com/mddblog/p/5215453.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末砍艾,一起剝皮案震驚了整個(gè)濱河市蒂教,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脆荷,老刑警劉巖悴品,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡苔严,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)孤澎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)届氢,“玉大人,你說(shuō)我怎么就攤上這事覆旭⊥俗樱” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵型将,是天一觀的道長(zhǎng)寂祥。 經(jīng)常有香客問(wèn)我,道長(zhǎng)七兜,這世上最難降的妖魔是什么丸凭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮腕铸,結(jié)果婚禮上惜犀,老公的妹妹穿的比我還像新娘。我一直安慰自己狠裹,他們只是感情好虽界,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著涛菠,像睡著了一般莉御。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俗冻,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天礁叔,我揣著相機(jī)與錄音,去河邊找鬼言疗。 笑死晴圾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的噪奄。 我是一名探鬼主播死姚,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼勤篮!你這毒婦竟也來(lái)了都毒?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤碰缔,失蹤者是張志新(化名)和其女友劉穎账劲,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瀑焦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年腌且,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榛瓮。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铺董,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出禀晓,到底是詐尸還是另有隱情精续,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布粹懒,位于F島的核電站重付,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏凫乖。R本人自食惡果不足惜确垫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拣凹。 院中可真熱鬧森爽,春花似錦、人聲如沸嚣镜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)菊匿。三九已至付呕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間跌捆,已是汗流浹背徽职。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留佩厚,地道東北人姆钉。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像抄瓦,于是被迫代替她去往敵國(guó)和親潮瓶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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