iOS中使用NSURLConnection處理HTTP同步與非同步請求_IOS

來源:互聯網
上載者:User

一、引言

在iOS7後,NSURLSession基本代替了NSURLConnection進行網路開發,在iOS9後,NSURLConnection相關方法被完全的棄用,iOS系統有向下相容的特性,儘管NSURLConnection已經被棄用,但在開發中,其方法依然可以被使用,並且如果需要相容到很低版本的iOS系統,有時就必須使用NSURLConnection類了。

二、使用NSURLConnection進行同步請求

對於網路請求分為同步和非同步兩種,同步是指在請求結果返回之前,程式碼會卡在請求處,之後的代碼不會被執行,非同步是指在發送請求之後,一邊在子線程中接收返回資料,一邊執行之後的代碼,當返回資料接收完畢後,採用回調的方式通知主線程做處理。

使用如下方法進行NSURLConnection的同步請求:

    NSURL * url = [NSURL URLWithString:@"http://www.baidu.com"];
    NSURLRequest * request = [NSURLRequest requestWithURL:url];
    NSData * data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    NSLog(@"%@",data);
    NSLog(@"繼續執行");
列印資訊如下圖所示,從中可以看出,當資料返回結束時才執行後面的代碼:

三、使用NSURLConnection進行非同步請求

使用同步的方式進行請求有一個很大的弊端,在進行網路請求時,資料的返回往往需要一定時間,不可能瞬間完成,使用同步的方式將導致介面卡死,沒有提示也不能互動任何使用者操作,這樣的話,很有可能會給使用者程式卡死的假象。

NSURLConnection類提供兩種方式進行非同步請求操作。

1.使用block的方式進行非同步請求

使用如下代碼進行block方式的非同步請求,在block中會傳入請求到的返回資料和資料資訊等參數:

    NSURL * url = [NSURL URLWithString:@"http://www.baidu.com"];
    NSURLRequest * request = [NSURLRequest requestWithURL:url];
    //其中的queue參數決定block中的代碼在哪個隊列中執行
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        NSLog(@"%@",data);
    }];
    NSLog(@"繼續執行");

2.使用代理回調的非同步請求方式

首先遵守協議與生命一個可變的NSData用於接收資料:

@interface ViewController ()<NSURLConnectionDataDelegate>
{
    NSMutableData * _data;
}
@end
使用如下的代碼進行請求:

    _data = [[NSMutableData alloc]init];
    NSURL * url = [NSURL URLWithString:@"http://www.baidu.com"];
    NSURLRequest * request = [NSURLRequest requestWithURL:url];
    [NSURLConnection connectionWithRequest:request delegate:self];
請求發出後,會一次調用如下代理方法進行請求過程的監聽和資料的擷取:

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    //開始接收資料
    [_data setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    //正在接收資料
    [_data appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    //接收資料失敗
    NSLog(@"%@",error);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
    //接收資料完成
    NSLog(@"%@",_data);
}

四、樣本
1.通過NSURLConnection進行非同步下載:  
NSURLConnection 提供了兩種方式來實現串連,一種是同步的另一種是非同步,非同步串連將會建立一個新的線程,這個線程將會來負責下載的動作。而對於同步串連,在下載串連和處理通訊時,則會阻塞當前調用線程。
許多開發人員都會認為同步的串連將會堵塞主線程,其實這種觀點是錯誤的。一個同步的串連是會阻塞調用它的線程。如果你在主線程中建立一個同步串連,沒錯,主線程會阻塞。但是如果你並不是從主線程開啟的一個同步的串連,它將會類似非同步串連一樣。因此這種情況並不會堵塞你的主線程。事實上,同步和非同步主要區別就是運行 runtime 為會非同步串連建立一個線程,而同步串連則不會。

//asynchronousRequest connection 
-(void)fetchAppleHtml{ 
    NSString *urlString = @"http://www.apple.com"; 
    NSURL *url = [NSURL URLWithString:urlString]; 
//    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; 
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:30.0f]; //maximal timeout is 30s 
     
    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
    [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 
        if ([data length] > 0 && connectionError == nil) { 
            NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
            NSString *filePath = [documentsDir stringByAppendingPathComponent:@"apple.html"]; 
            [data writeToFile:filePath atomically:YES]; 
            NSLog(@"Successfully saved the file to %@",filePath); 
            NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
            NSLog(@"HTML = %@",html); 
        }else if ([data length] == 0 && connectionError == nil){ 
            NSLog(@"Nothing was downloaded."); 
        }else if (connectionError != nil){ 
            NSLog(@"Error happened = %@",connectionError); 
        } 
    }]; 

2.通過NSURLConnection進行同步下載:
使用 NSURLConnection 的 sendSynchronousRequest:returningResponse:error:類方法,我們可以進行同步請求。在建立一個同步的網路連接的時候我們需要明白一點,並不是是我們的這個同步串連一定會堵塞我們的主線程,如果這個同步的串連是建立在主線程上的,那麼這種情況下是會堵塞我們的主線程的,其他的情況下是不一定會堵塞我們的主線程的。如果你在 GCD 的全域並發隊列上初始化了一個同步的串連,你其實並不會堵塞我們的主線程的。
我們來初始化第一個同步串連,並看看會發生什麼。在執行個體中,我們將嘗試擷取 Yahoo!美國網站首頁內容:

//synchronousRequest connection 
-(void)fetchYahooData{ 
    NSLog(@"We are here..."); 
    NSString *urlString = @"http://www.yahoo.com"; 
    NSURL *url = [NSURL URLWithString:urlString]; 
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; 
    NSURLResponse *response = nil; 
    NSError *error = nil; 
    NSLog(@"Firing synchronous url connection..."); 
    NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error]; 
    if ([data length] > 0 && error == nil) { 
        NSLog(@"%lu bytes of data was returned.",(unsigned long)[data length]); 
    }else if([data length] == 0 && error == nil){ 
        NSLog(@"No data was return."); 
    }else if (error != nil){ 
        NSLog(@"Error happened = %@",error); 
    } 
    NSLog(@"We are done."); 
     

/*
 |
 | as we know, it will chock main thread when we call sendSynchronousRequest on main thread,,,,change below
 |
 v
*/ 
//call sendSynchronousRequest on GCD pool 
-(void)fetchYahooData2_GCD{ 
    NSLog(@"We are here..."); 
    NSString *urlString = @"http://www.yahoo.com"; 
    NSLog(@"Firing synchronous url connection..."); 
    dispatch_queue_t dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(dispatchQueue, ^{ 
        NSURL *url = [NSURL URLWithString:urlString]; 
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; 
        NSURLResponse *response = nil; 
        NSError *error = nil; 
        NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error]; 
        if ([data length] > 0 && error == nil) { 
            NSLog(@"%lu bytes of data was returned.",(unsigned long)[data length]); 
        }else if ([data length] == 0 && error == nil){ 
            NSLog(@"No data was returned."); 
        }else if (error != nil){ 
            NSLog(@"Error happened = %@",error); 
        } 
    }); 
    NSLog(@"We are done."); 
 

查看運行輸出結果,分別為:
synchronous download on main thread without GCD

synchronous download on main thread with GCD

可以看到在主線程上調用同步下載會阻塞當前線程,而使用GCD則不會。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.