NSURLConnection

基本使用

  • 通過NSURLConnection發(fā)送請求常用的類

    • NSURL : 用于創(chuàng)建網(wǎng)絡(luò)請求地址
    • NSURLRequest : 一個(gè)NSURLRequest對象就代表一個(gè)請求
      包含的信息如下:
      1. 一個(gè)NSURL對象
      2.請求方法,請求體,請求頭
      3.請求超時(shí)
      ......
    • NSURLConnection的作用:
      1.負(fù)責(zé)發(fā)送請求,簡歷客戶端與服務(wù)器之間的連接
      2.發(fā)送數(shù)據(jù)給服務(wù)器,并收集來自服務(wù)器的響應(yīng)數(shù)據(jù)
  • NSURLConnection的使用步驟
    1.創(chuàng)建一個(gè)NSURL對象
    2.通過創(chuàng)建的NSURL對象,創(chuàng)建一個(gè)NSURLRequest請求對象,并設(shè)置請求頭和請求體
    3.定義一個(gè)響應(yīng)對象, 直接賦值為 nil 用于接收響應(yīng)的數(shù)據(jù)
    一般使用 NSURLResponse 的子類 NSHTTPURLResponse
    3.使用NSURLConnection發(fā)送請求

  • NSURLConnection發(fā)送請求的常見的集中方式
    1.同步請求(GET-SendSync)
    2.異步請求(GET-SendAsync)
    3.異步請求(GET-代理)
    4.發(fā)送POST請求

    • 同步GET請求
      方法 : sendSynchronousRequest:request returningResponse:&response error:
      **參數(shù)解析 : **
      第一個(gè)參數(shù): 是請求對象
      第二個(gè)參數(shù): 是接收響應(yīng)對象的地址 NSURLConnection同步請求就只有這個(gè)方法, 該方法是有返回值的, 返回值類型 NSData
      **注意 : **阻塞式的方法,會卡住線程
-(void)sendSync
{
        //1.確定請求路徑
        NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=XML"];

        //2.創(chuàng)建一個(gè)請求對象
        //該方法內(nèi)部會提供一個(gè)默認(rèn)的請求頭信息 | 默認(rèn)發(fā)送的就是GET請求
        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        //3.把請求發(fā)送給服務(wù)器
        //設(shè)置響應(yīng)對象    NSHTTPURLResponse是NSURLResponse的子類
        NSHTTPURLResponse *response = nil;
        NSError *error = nil;

        /*
        第一個(gè)參數(shù):請求對象
        第二個(gè)參數(shù):響應(yīng)頭信息,當(dāng)該方法執(zhí)行完畢之后,該參數(shù)被賦值
        第三個(gè)參數(shù):錯(cuò)誤信息,如果請求失敗,則error有值
        */
        //該方法是阻塞式的,會卡住線程
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

        //4.解析服務(wù)器返回的數(shù)據(jù)
        NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
}
  • 異步GET請求
    方法 : sendAsynchronousRequest:queue:completionHandler:NSURLConnection異步請求, 也只有這一個(gè)方法
    **參數(shù)解析 : **第二個(gè)參數(shù)傳輸?shù)氖顷?duì)列, 表示的是回調(diào)是在哪個(gè)線程中回調(diào)
    **注意 : **該方法不會卡住當(dāng)前線程,網(wǎng)絡(luò)請求任務(wù)是異步執(zhí)行的
-(void)sendAsync
{
       //1.確定請求路徑
        NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it"];

        //2.創(chuàng)建一個(gè)請求對象
        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        //3.把請求發(fā)送給服務(wù)器,發(fā)送一個(gè)異步請求
        /*
        第一個(gè)參數(shù):請求對象
        第二個(gè)參數(shù):回調(diào)方法在哪個(gè)線程中執(zhí)行,如果是主隊(duì)列則block在主線程中執(zhí)行,非主隊(duì)列則在子線程中執(zhí)行
        第三個(gè)參數(shù):completionHandlerBlock塊:接受到響應(yīng)的時(shí)候執(zhí)行該block中的代碼
                response:響應(yīng)頭信息
                data:響應(yīng)體
                connectionError:錯(cuò)誤信息,如果請求失敗,那么該參數(shù)有值
             */
        [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse * __nullable response, NSData * __nullable data, NSError * __nullable connectionError) {

            //請求失敗返回的connectionError才會有值,不是看輸入的用戶名和密碼是不是正確
            if (connectionError == nil) {
                  //4.解析服務(wù)器返回的數(shù)據(jù)
                  NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
                  //轉(zhuǎn)換并打印響應(yīng)頭信息
                  NSHTTPURLResponse *r = (NSHTTPURLResponse *)response;
                  NSLog(@"--%zd---%@--",r.statusCode,r.allHeaderFields);
        }
        }];
}
  • 異步請求(GET-代理)
    **方法一 : **一個(gè)類方法創(chuàng)建對象, 設(shè)置代理,并自動開啟請 求 connectionWithRequest:delegate:
    **方法二 : **有兩個(gè) alloc / initWithRequest...創(chuàng)建方法
    alloc / initWithRequest: delegate:需要手動調(diào)用 start 開 啟網(wǎng)絡(luò)請求
    alloc / initWithRequest: delegate: startImmediately:
    第二個(gè)alloc / init是根據(jù)最后一 個(gè)參數(shù)的Bool值, 如果為 YES, 則馬上自行開啟網(wǎng)絡(luò)請求, 如果為 NO 則也是要手動調(diào)用 start
    • 可以設(shè)置代理方法在哪個(gè)線程中執(zhí)行
      通過- setDelegateQueue: 對象方法, 設(shè)置這只代理在哪個(gè)線程中執(zhí)行; 默認(rèn)情況下,代理方法會在主線程中進(jìn)行調(diào)用(為了方便開發(fā)者拿到 數(shù)據(jù)后處理一些刷新UI的操作不需要考慮到線程間通信)
    • **步驟 : **
      (1)確定請求路徑
      (2)創(chuàng)建請求對象
      (3)創(chuàng)建NSURLConnection對象并設(shè)置代理
      (4)遵守NSURLConnectionDataDelegate協(xié)議,并實(shí)現(xiàn)相應(yīng)的代理方法
      (5)在代理方法中監(jiān)聽網(wǎng)絡(luò)請求的響應(yīng)
              -(void)sendAsyncDelegate
            {
                //1.創(chuàng)建請求的url路徑
                NSURL * url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520&pwd=520it&type=JSON"];
                //2.創(chuàng)建請求對象
                NSURLRequest * request = [NSURLRequest requestWithURL:url];
                //3.設(shè)置代理發(fā)送請求
                //方法一
                //    NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
                //注意:通過這個(gè)方法設(shè)置的代理,并發(fā)送的請求,是不需要手動開啟的,方法默認(rèn)會自動開啟
      
                //方法二
                //注意:參數(shù)startImmediately如果傳的是YES,那么這個(gè)方法的效果和方法一設(shè)置代理的效果是一樣的
                //  如果傳的是NO,那么就需要手動發(fā)送網(wǎng)絡(luò)請求
                //    NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
                //    [connection start];//如果不手動發(fā)送網(wǎng)絡(luò)請求,那么程序是不會有任何反應(yīng)
      
                //方式三:類工廠方法,和方式一一樣
                [NSURLConnection connectionWithRequest:request delegate:self];
                //取消網(wǎng)絡(luò)請求
                //[conn cancel];
             }
      
      • 相應(yīng)的代理方法
         1.當(dāng)接收到服務(wù)器響應(yīng)的時(shí)候調(diào)用
         //第一個(gè)參數(shù)connection:監(jiān)聽的是哪個(gè)NSURLConnection對象
         //第二個(gè)參數(shù)response:接收到的服務(wù)器返回的響應(yīng)頭信息
        - (void)connection:(nonnull NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response

         2.當(dāng)接收到數(shù)據(jù)的時(shí)候調(diào)用,該方法會被調(diào)用多次
         //第一個(gè)參數(shù)connection:監(jiān)聽的是哪個(gè)NSURLConnection對象
         //第二個(gè)參數(shù)data:本次接收到的服務(wù)端返回的二進(jìn)制數(shù)據(jù)(可能是片段)
        - (void)connection:(nonnull NSURLConnection *)connection didReceiveData:(nonnull NSData *)data

         3.當(dāng)服務(wù)端返回的數(shù)據(jù)接收完畢之后會調(diào)用
         //通常在該方法中解析服務(wù)器返回的數(shù)據(jù)
        -(void)connectionDidFinishLoading:(nonnull NSURLConnection *)connection

         4.當(dāng)請求錯(cuò)誤的時(shí)候調(diào)用(比如請求超時(shí))
         //第一個(gè)參數(shù)connection:NSURLConnection對象
         //第二個(gè)參數(shù):網(wǎng)絡(luò)請求的錯(cuò)誤信息,如果請求失敗,則error有值
        - (void)connection:(nonnull NSURLConnection *)connection didFailWithError:(nonnull NSError *)error
  • **補(bǔ)充 : **
字符串截取相關(guān)方法
        - (NSRange)rangeOfString:(NSString *)searchString;
        - (NSString *)substringWithRange:(NSRange)range;
  • 發(fā)送POST請求
    • **步驟 : **
      a.確定URL路徑
      b.創(chuàng)建請求對象(可變對象 ,因?yàn)橹挥性诳勺儗ο笙?才能修改請求對象的請求方法)
      c.修改請求對象的方法為POST(POST必須大寫)
      1.通過HTTPMethod 屬性, 修改請求對象的方法為POST<必須大寫>
      2.設(shè)置請求頭部信息
      3.timeoutInterval 屬性, 請求響應(yīng)等待時(shí)間(一般是15s)
      d.設(shè)置請求體(Data)
      1.HTTPBody 屬性, 設(shè)置請求體信息
      2.字符串轉(zhuǎn)為(二進(jìn)制)編碼格式
      3.type=JSON 可以不傳, 不傳默認(rèn)就是 JSON 格式, 開發(fā)中最好都寫上
      e.發(fā)送一個(gè)異步請求
      "sendAsynchronousRequest: queue:"
      1.同步和異步各自只有一個(gè)類方法, 發(fā)送請求
      2.該方法第二個(gè)參數(shù): 隊(duì)列,只是決定后面的第三個(gè)參數(shù) block塊, 在哪個(gè) 線程中回調(diào)
      f.解析數(shù)據(jù)(解析的是響應(yīng)體 data 的數(shù)據(jù)) 將二進(jìn)制數(shù)據(jù)轉(zhuǎn)字符串
-(void)post{
            //1.創(chuàng)建訪問餓url路徑
            //注意:以POST方式發(fā)送的請求的url沒有"?"
            NSURL * url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
          
            //2.創(chuàng)建請求體
            //注意:要是想要設(shè)置發(fā)送請求方式為POST,就需要是可變的request
            NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
           //2.1設(shè)置發(fā)送請求的方式為POST
            request.HTTPMethod = @"POST";
           //2.2設(shè)置請求體
            request.HTTPBody = [@"username=520it&pwd=520&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
            //2.3設(shè)置請求時(shí)間
            request.timeoutInterval = 15;
            //2.4設(shè)置請求頭中的信息
            //    [request setValue:@"iOS 10.1" forHTTPHeaderField:@"User-Agent"];

            //3.發(fā)送請求
            [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
       
            //4.解析服務(wù)器返回的數(shù)據(jù)
                    if (connectionError) {
                        NSLog(@"--請求失敗-");
                    }else{
                        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
                    }
    }];
}

URL中文轉(zhuǎn)碼

**轉(zhuǎn)碼的方法 : **stringByAddingPercentEscapesUsingEncoding:
**原因 : **URL是不支持中文, 因此如果URL字符串中包含中文那么在發(fā)送請求之前需要 對URL進(jìn)行中文轉(zhuǎn)碼
**注意 : **瀏覽器中的 http 的鏈接有時(shí)候可以看到有中文, 其實(shí)URL內(nèi)部已經(jīng)做了轉(zhuǎn) 碼處理
**如何對URL進(jìn)行轉(zhuǎn)碼 : **stringByAddingPercentEscapesUsingEncoding
**建議 : **不管有沒有中文字符, 都寫上轉(zhuǎn)碼, 這樣擴(kuò)展性比較好

//獲取url的字符串
NSString *urlStr = @"http://120.25.226.186:32812/login2?username=小碼哥&pwd=520it";
    NSLog(@"%@",urlStr);
    //中文轉(zhuǎn)碼操作
    urlStr =  [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"%@",urlStr);
//根絕轉(zhuǎn)碼后的url字符串創(chuàng)建NSURL對象
    NSURL *url = [NSURL URLWithString:urlStr];

NSURLConnection和Runloop

1 兩種為NSURLConnection設(shè)置代理方式的區(qū)別

    //第一種設(shè)置方式:
    //通過該方法設(shè)置代理,會自動的發(fā)送請求
    // [[NSURLConnection alloc]initWithRequest:request delegate:self];

    //第二種設(shè)置方式:
    //設(shè)置代理,startImmediately為NO的時(shí)候,該方法不會自動發(fā)送請求
    NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO];
    //手動通過代碼的方式來發(fā)送請求
    //注意該方法內(nèi)部會自動的把connect添加到當(dāng)前線程的RunLoop中在默認(rèn)模式下執(zhí)行
    [connect start];

2 如何控制代理方法在哪個(gè)線程調(diào)用

    //說明:默認(rèn)情況下,代理方法會在主線程中進(jìn)行調(diào)用(為了方便開發(fā)者拿到數(shù)據(jù)后處理一些刷新UI的操作不需要考慮到線程間通信)
    //設(shè)置代理方法的執(zhí)行隊(duì)列
    [connect setDelegateQueue:[[NSOperationQueue alloc]init]];

3 開子線程發(fā)送網(wǎng)絡(luò)請求的注意點(diǎn),適用于自動發(fā)送網(wǎng)絡(luò)請求模式

    //在子線程中發(fā)送網(wǎng)絡(luò)請求-調(diào)用startf方法發(fā)送
    -(void)createNewThreadSendConnect1
    {
        //1.創(chuàng)建一個(gè)非主隊(duì)列
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];

        //2.封裝操作,并把任務(wù)添加到隊(duì)列中執(zhí)行
        [queue addOperationWithBlock:^{

            NSLog(@"%@",[NSThread currentThread]);
            //2-1.確定請求路徑
            NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=dd&pwd=ww&type=JSON"];

            //2-2.創(chuàng)建請求對象
            NSURLRequest *request = [NSURLRequest requestWithURL:url];

            //2-3.使用NSURLConnection設(shè)置代理,發(fā)送網(wǎng)絡(luò)請求
            NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];

            //2-4.設(shè)置代理方法在哪個(gè)隊(duì)列中執(zhí)行,如果是非主隊(duì)列,那么代理方法將再子線程中執(zhí)行
            [connection setDelegateQueue:[[NSOperationQueue alloc]init]];

            //2-5.發(fā)送網(wǎng)絡(luò)請求
            //注意:start方法內(nèi)部會把當(dāng)前的connect對象作為一個(gè)source添加到當(dāng)前線程對應(yīng)的runloop中
            //區(qū)別在于,如果調(diào)用start方法開發(fā)送網(wǎng)絡(luò)請求,那么再添加source的過程中,如果當(dāng)前runloop不存在
            //那么該方法內(nèi)部會自動創(chuàng)建一個(gè)當(dāng)前線程對應(yīng)的runloop,并啟動。
            [connection start];

        }];
    }

    //在子線程中發(fā)送網(wǎng)絡(luò)請求-自動發(fā)送網(wǎng)絡(luò)請求
    -(void)createNewThreadSendConnect2
    {
        NSLog(@"-----");
        //1.創(chuàng)建一個(gè)非主隊(duì)列
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];

        //2.封裝操作,并把任務(wù)添加到隊(duì)列中執(zhí)行
        [queue addOperationWithBlock:^{

            //2-1.確定請求路徑
            NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=dd&pwd=ww&type=JSON"];

            //2-2.創(chuàng)建請求對象
            NSURLRequest *request = [NSURLRequest requestWithURL:url];

            //2-3.使用NSURLConnection設(shè)置代理,發(fā)送網(wǎng)絡(luò)請求
            //注意:該方法內(nèi)部雖然會把connection添加到runloop,但是如果當(dāng)前的runloop不存在,那么不會主動創(chuàng)建。
            NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];

            //2-4.設(shè)置代理方法在哪個(gè)隊(duì)列中執(zhí)行,如果是非主隊(duì)列,那么代理方法將再子線程中執(zhí)行
            [connection setDelegateQueue:[[NSOperationQueue alloc]init]];

            //2-5 創(chuàng)建當(dāng)前線程對應(yīng)的runloop,并開啟(因?yàn)檫@個(gè)方法不會自動創(chuàng)建一個(gè)線程供NSURLConnection對象發(fā)送網(wǎng)絡(luò)請求)
           [[NSRunLoop currentRunLoop]run];
        }];
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容