NSURLConnection

基本使用

  • 通過NSURLConnection發送請求常用的類

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

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

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

        //2.創建一個請求對象
        //該方法內部會提供一個默認的請求頭信息 | 默認發送的就是GET請求
        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        //3.把請求發送給服務器
        //設置響應對象    NSHTTPURLResponse是NSURLResponse的子類
        NSHTTPURLResponse *response = nil;
        NSError *error = nil;

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

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

        //2.創建一個請求對象
        NSURLRequest *request = [NSURLRequest requestWithURL:url];

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

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

         2.當接收到數據的時候調用,該方法會被調用多次
         //第一個參數connection:監聽的是哪個NSURLConnection對象
         //第二個參數data:本次接收到的服務端返回的二進制數據(可能是片段)
        - (void)connection:(nonnull NSURLConnection *)connection didReceiveData:(nonnull NSData *)data

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

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

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

URL中文轉碼

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

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

NSURLConnection和Runloop

1 兩種為NSURLConnection設置代理方式的區別

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

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

2 如何控制代理方法在哪個線程調用

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

3 開子線程發送網絡請求的注意點,適用于自動發送網絡請求模式

    //在子線程中發送網絡請求-調用startf方法發送
    -(void)createNewThreadSendConnect1
    {
        //1.創建一個非主隊列
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];

        //2.封裝操作,并把任務添加到隊列中執行
        [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.創建請求對象
            NSURLRequest *request = [NSURLRequest requestWithURL:url];

            //2-3.使用NSURLConnection設置代理,發送網絡請求
            NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];

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

            //2-5.發送網絡請求
            //注意:start方法內部會把當前的connect對象作為一個source添加到當前線程對應的runloop中
            //區別在于,如果調用start方法開發送網絡請求,那么再添加source的過程中,如果當前runloop不存在
            //那么該方法內部會自動創建一個當前線程對應的runloop,并啟動。
            [connection start];

        }];
    }

    //在子線程中發送網絡請求-自動發送網絡請求
    -(void)createNewThreadSendConnect2
    {
        NSLog(@"-----");
        //1.創建一個非主隊列
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];

        //2.封裝操作,并把任務添加到隊列中執行
        [queue addOperationWithBlock:^{

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

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

            //2-3.使用NSURLConnection設置代理,發送網絡請求
            //注意:該方法內部雖然會把connection添加到runloop,但是如果當前的runloop不存在,那么不會主動創建。
            NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];

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

            //2-5 創建當前線程對應的runloop,并開啟(因為這個方法不會自動創建一個線程供NSURLConnection對象發送網絡請求)
           [[NSRunLoop currentRunLoop]run];
        }];
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容