網(wǎng)絡(luò)請求-NSURLSession 和 AFNNetworking

1.NSURLSession概述

1. NSURLSession session類型

NSURLSession包括下面3種session類型

a). Default session(默認(rèn)會話模式):
使用的是基于磁盤緩存的持久化策略,工作模式類似于原來的NSURLConnection灭美,可以用來取代NSURLConnection中的:

[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]

b). Ephemeral session(瞬時會話模式):
臨時的進(jìn)程內(nèi)會話(內(nèi)存)泞莉,不會將cookie、證書嚣伐、緩存儲存到本地,只會放到內(nèi)存中,當(dāng)應(yīng)用程序退出后數(shù)據(jù)也會消失。

c). Background session(后臺會話模式):
和默認(rèn)會話模式類似, 不過相比默認(rèn)模式吹由,該會話會在后臺開啟一個線程進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)處理。

//Default session
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;
 
//Ephemeral
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
 
//Background 
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier;

你需要了解包括NSURLSession朱嘴、NSURLSessionConfiguration 以及 NSURLSessionTask 的 3 個子類:NSURLSessionDataTask倾鲫,NSURLSessionUploadTask粗合,NSURLSessionDownloadTask。

與 NSURLConnection 相比乌昔,NSURLsession 最直接的改進(jìn)就是可以配置每個 session 的緩存隙疚,協(xié)議,cookie磕道,以及證書策略供屉,甚至跨程序共享這些信息。這將允許程序和網(wǎng)絡(luò)基礎(chǔ)框架之間相互獨立溺蕉,不會發(fā)生干擾伶丐。每個 NSURLSession 對象都由一個 NSURLSessionConfiguration 對象來進(jìn)行初始化。

NSURLSession 中另一大塊就是 session task疯特。它負(fù)責(zé)處理數(shù)據(jù)的加載以及文件和數(shù)據(jù)在客戶端與服務(wù)端之間的上傳和下載哗魂。NSURLSessionTask 與 NSURLConnection 最大的相似之處在于它也負(fù)責(zé)數(shù)據(jù)的加載,最大的不同之處在于所有的 task 共享其創(chuàng)造者 NSURLSession 這一公共委托者(common delegate)漓雅。

2.NSURLSessionTask類

NSURLSessionTask是一個抽象子類录别,它有三個子類:NSURLSessionDataTask,NSURLSessionUploadTask和NSURLSessionDownloadTask故硅。這三個類封裝了現(xiàn)代應(yīng)用程序的三個基本網(wǎng)絡(luò)任務(wù):獲取數(shù)據(jù),比如JSON或XML纵搁,以及上傳和下載文件吃衅。

下面是其繼承關(guān)系:

不同于直接使用 alloc-init 初始化方法,task 是由一個 NSURLSession 創(chuàng)建的腾誉。每個 task 的構(gòu)造方法都對應(yīng)有或者沒有 completionHandler 這個 block 的兩個版本徘层。

1).NSURLSessionDataTask

NSURLSessionDataTask使用NSData來交換數(shù)據(jù). NSURLSessionDataTask不支持后臺會話模式。

a) 通過request對象或url創(chuàng)建
//通過一個給定的請求
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
 
//通過一個給定的URL.
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;

代理方法:

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
    completionHandler(NSURLSessionResponseAllow);
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    //data: response from the server.
}
b).通過request對象或url創(chuàng)建利职,同時指定任務(wù)完成后通過completionHandler指定回調(diào)的代碼塊:
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

2).NSURLSessionDownloadTask

a).通過URL/request/resumeData創(chuàng)建
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;
 
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;

//下載任務(wù)支持?jǐn)帱c續(xù)傳趣效,這種方式是通過之前已經(jīng)下載的數(shù)據(jù)來創(chuàng)建下載任務(wù)。
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;

代理方法:

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                              didFinishDownloadingToURL:(NSURL *)location;
 
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                           didWriteData:(int64_t)bytesWritten
                                      totalBytesWritten:(int64_t)totalBytesWritten
                              totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
 
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                      didResumeAtOffset:(int64_t)fileOffset
                                     expectedTotalBytes:(int64_t)expectedTotalBytes;

b).通過completionHandler指定任務(wù)完成后的回調(diào)代碼塊:
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler;

3).NSURLSessionUploadTask

a).通過request創(chuàng)建猪贪,在上傳時指定文件源或數(shù)據(jù)源跷敬。
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;
 
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;

代理方法:

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                                didSendBodyData:(int64_t)bytesSent
                                 totalBytesSent:(int64_t)totalBytesSent
                       totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;
b).通過completionHandler指定任務(wù)完成后的回調(diào)代碼塊
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

3.NSURLSession類

從上面我們已經(jīng)知道創(chuàng)建一個NSURLSessionTask需要NSURLSession,獲取NSURLSession類對象有幾種方式:

//使用全局的Cache热押,Cookie和證書西傀。
+ (NSURLSession *)sharedSession;  

//創(chuàng)建對應(yīng)配置的會話。   
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;  

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

第三種方式指定了session的委托和委托所處的隊列桶癣。當(dāng)不再需要連接時拥褂,可以調(diào)用Session的invalidateAndCancel直接關(guān)閉,或者調(diào)用finishTasksAndInvalidate等待當(dāng)前Task結(jié)束后關(guān)閉牙寞。這時Delegate會收到URLSession:didBecomeInvalidWithError:這個事件饺鹃。Delegate收到這個事件之后會被解引用。

3.NSURLSessionConfiguration類

上面2、3種創(chuàng)建方式使用了NSURLSessionConfiguration悔详,它用于配置會話的屬性镊屎,創(chuàng)建方法如下:

+ (NSURLSessionConfiguration *)defaultSessionConfiguration;  

+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;  

//identifier參數(shù)指定了會話的ID,用于標(biāo)記后臺的session伟端。
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier; 

這個類有兩個屬性:

@property BOOL allowsCellularAccess;  

@property (getter=isDiscretionary) BOOL discretionary NS_AVAILABLE(NA, 7_0);

allowsCellularAccess 屬性指定是否允許使用蜂窩連接杯道, discretionary屬性為YES時表示當(dāng)程序在后臺運作時由系統(tǒng)自己選擇最佳的網(wǎng)絡(luò)連接配置,該屬性可以節(jié)省通過蜂窩連接的帶寬责蝠。在使用后臺傳輸數(shù)據(jù)的時候党巾,建議使用discretionary屬性,而不是allowsCellularAccess屬性霜医,因為它會把WiFi和電源可用性考慮在內(nèi)齿拂。

2.實例

創(chuàng)建一個NSURLSession任務(wù)需要遵循以下步驟:
a)創(chuàng)建一個Session Configuration
b)創(chuàng)建一個NSURLSession
c) 創(chuàng)建一個NSURLSession Task ( Data,Download or Upload)
d)代理方法
e)調(diào)用resume方法

1.數(shù)據(jù)請求

前面通過請求一個NSURLSessionDataTask進(jìn)行數(shù)據(jù)請求演示:

- (IBAction)loadData:(UIButton *)sender {
    // 創(chuàng)建Data Task,
    NSURL *url = [NSURL URLWithString:@"http://www.reibang.com/users/9tsPFp/latest_articles"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                                completionHandler:
                                      ^(NSData *data, NSURLResponse *response, NSError *error) {
                                          // 輸出返回的狀態(tài)碼肴敛,請求成功的話為200
                                          if (!error) {
                                              [self showResponseCode:response];
                                          }else{
                                              NSLog(@"error is :%@",error.localizedDescription);
                                          }
                                      }];
    // 使用resume方法啟動任務(wù)
    [dataTask resume];
}

- (void)showResponseCode:(NSURLResponse *)response {
    NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
    NSInteger responseStatusCode = [httpResponse statusCode];
    NSLog(@"狀態(tài)碼--%ld", (long)responseStatusCode);
}

2.HTTP GET和POST

1).GET

我們使用豆瓣的API來演示這個GET請求

- (IBAction)GETRequest:(id)sender {
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *delegateFreeSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
    
    NSURL * url = [NSURL URLWithString:@"https://api.douban.com/v2/book/1220562"];
    
    NSURLSessionDataTask * dataTask = [delegateFreeSession dataTaskWithURL:url
                                                         completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                             if(error == nil)
                                                             {
                                                                 NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
                                                                 NSLog(@"GET請求數(shù)據(jù)= %@",text);
                                                             }
                                                             
                                                         }];
    
    [dataTask resume];
}

數(shù)據(jù)請求結(jié)果如下:

2).POST

我們使用http://hayageek.com/examples/jquery/ajax-post/ajax-post.php 這個接口來演示POST請求署海,POST需要4個參數(shù): name, loc, age, submit,如下:

- (IBAction)POSTRequest:(UIButton *)sender {
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *delegateFreeSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
    
    
    NSURL * url = [NSURL URLWithString:@"http://hayageek.com/examples/jquery/ajax-post/ajax-post.php"];
    NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
    NSString * params =@"name=Ravi&loc=India&age=31&submit=true";
    [urlRequest setHTTPMethod:@"POST"];
    [urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
    
    
    NSURLSessionDataTask * dataTask =[delegateFreeSession dataTaskWithRequest:urlRequest
                                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                                NSLog(@"Response:%@ %@\n", response, error);
                                                                if(error == nil)
                                                                {
                                                                    NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
                                                                    NSLog(@"POST返回數(shù)據(jù) = %@",text);
                                                                }
                                                                
                                                            }];
    [dataTask resume];

}

返回數(shù)據(jù):

Response:<NSHTTPURLResponse: 0x7ff948778240> { URL: http://hayageek.com/examples/jquery/ajax-post/ajax-post.php } { status code: 200, headers {
    Connection = "keep-alive";
    "Content-Encoding" = gzip;
    "Content-Type" = "text/html";
    Date = "Wed, 18 Mar 2015 01:43:07 GMT";
    Server = nginx;
    "Transfer-Encoding" = Identity;
    Vary = "Accept-Encoding, Accept-Encoding";
    "X-Powered-By" = "EasyEngine 2.0.0";
} } (null)
2015-03-18 09:43:10.418 WebConnectionDemo[28129:2666176] POST返回數(shù)據(jù) = Data from server: {"name":"Ravi","loc":"India","age":"31","submit":"true"}<br>

3.NSURLSessionUploadTask

Upload task 的創(chuàng)建需要使用一個 request医男,另外加上一個要上傳的 NSData 對象或者是一個本地文件的路徑對應(yīng)的 NSURL砸狞,類似的代碼如下:

NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];
 NSData *data = ...;

 NSURLSession *session = [NSURLSession sharedSession];
 NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
                                                            fromData:data
                                                   completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
         // ...
     }];

 [uploadTask resume];

4.NSURLSessionDownloadTask

a.普通下載

- (IBAction)download:(id)sender {
    NSURL * url = [NSURL URLWithString:@"http://e.hiphotos.baidu.com/image/pic/item/63d0f703918fa0ec14b94082249759ee3c6ddbc6.jpg"];
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];
    
    NSURLSessionDownloadTask * downloadTask =[ defaultSession downloadTaskWithURL:url];
    [downloadTask resume];
}

為了實現(xiàn)下載進(jìn)度的顯示,需要在委托中的以下方法中實現(xiàn):

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    float progress = totalBytesWritten*1.0/totalBytesExpectedToWrite;
    dispatch_async(dispatch_get_main_queue(),^ {
        [self.process setProgress:progress animated:YES];
    });
    NSLog(@"Progress =%f",progress);
    NSLog(@"Received: %lld bytes (Downloaded: %lld bytes)  Expected: %lld bytes.\n",
          bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}

Download task 是將數(shù)據(jù)一點點地寫入本地的臨時文件镀梭。我們需要把文件從一個臨時地址移動到一個永久的地址保存起來::

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    NSLog(@"Temporary File :%@\n", location);
    NSError *err = nil;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
   
    NSURL *docsDirURL = [NSURL fileURLWithPath:[docsDir stringByAppendingPathComponent:@"out1.zip"]];
    if ([fileManager moveItemAtURL:location
                             toURL:docsDirURL
                             error: &err])
    {
        NSLog(@"File is saved to =%@",docsDir);
    }
    else
    {
        NSLog(@"failed to move: %@",[err userInfo]);
    }
}

如下所示:

b.可取消的下載

我們將做一些改動刀森,使其支持取消下載,先創(chuàng)建一個全局NSURLSessionDownloadTask對象:

@property (strong, nonatomic) NSURLSessionDownloadTask *cancellableTask;

調(diào)用cancle方法即可取消:

- (IBAction)cancleDownload:(UIButton *)sender {
    if (self.cancellableTask) {
        [self.cancellableTask cancel];
        self.cancellableTask = nil;
    }
}

這樣點擊cancle按鈕后下載任務(wù)會取消报账,重新點擊下載會從最初的經(jīng)度條開始下載研底。

c.斷點續(xù)傳下載

斷點續(xù)傳,我們需要一個NSData來暫存我們下載的數(shù)據(jù):

@property (strong, nonatomic) NSData *partialData;

download方法中做以下改動透罢,如果已經(jīng)有緩存的數(shù)據(jù)榜晦,即使用downloadTaskWithResumeData進(jìn)行下載:

- (IBAction)download:(UIButton *)sender {
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];
    
    if (self.partialData) {
        self.cancellableTask = [defaultSession downloadTaskWithResumeData:self.partialData];
    }
    else{
    NSURL * url = [NSURL URLWithString:@"http://e.hiphotos.baidu.com/image/pic/item/63d0f703918fa0ec14b94082249759ee3c6ddbc6.jpg"];
    self.cancellableTask =[ defaultSession downloadTaskWithURL:url];
    }
    [self.cancellableTask resume];
}

cancle方法也需要做改動,我們需要保存我們已下載的數(shù)據(jù):

- (IBAction)cancleDownload:(UIButton *)sender {
    if (self.cancellableTask) {
        [self.cancellableTask cancelByProducingResumeData:^(NSData *resumeData) {
            self.partialData = resumeData;
        }];
        self.cancellableTask = nil;
    }
}

另外恢復(fù)下載時羽圃,NSURLSessionDownloadDelegate中的以下方法將被調(diào)用:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{
    NSLog(@"NSURLSessionDownloadDelegate: Resume download at %lld", fileOffset);
}

如下:

6.后臺下載

首先創(chuàng)建一個全局對象:

@property (strong, nonatomic) NSURLSessionDownloadTask * backgroundDownloadTask;

配置下載任務(wù):

- (IBAction)downoadBackground:(id)sender {
    NSURL * url = [NSURL URLWithString:@"https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/CocoaEncyclopedia.pdf"];
    NSURLSessionConfiguration * backgroundConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"backgroundtask1"];
    
    NSURLSession *backgroundSeesion = [NSURLSession sessionWithConfiguration: backgroundConfig delegate:self delegateQueue: [NSOperationQueue mainQueue]];
    
    self.backgroundDownloadTask =[ backgroundSeesion downloadTaskWithURL:url];
    [self.backgroundDownloadTask resume];
}

在程序進(jìn)入后臺后乾胶,如果下載任務(wù)完成,AppDelegate中的對應(yīng)方法將被調(diào)用:

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
    NSLog(@"Save completionHandler");
    self.completionHandler = completionHandler;
}

然后修改上面那個協(xié)議方法朽寞,如下:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    if (downloadTask == self.cancellableTask) {
        NSLog(@"Temporary File :%@\n", location);
        NSError *err = nil;
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        
        NSURL *docsDirURL = [NSURL fileURLWithPath:[docsDir stringByAppendingPathComponent:@"out1.zip"]];
        if ([fileManager moveItemAtURL:location
                                 toURL:docsDirURL
                                 error: &err]){
            NSLog(@"File is saved to =%@",docsDir);
        }
        else{
            NSLog(@"failed to move: %@",[err userInfo]);
        }
    }else if(downloadTask == self.backgroundDownloadTask){
        NSLog(@"Background URL session %@ finished events.\n", session);
        
        AppDelegate * delegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
        if(delegate.completionHandler)
        {
            void (^handler)() = delegate.completionHandler;
            handler();
        }
    }
}

運行程序并退出當(dāng)前程序后打印結(jié)果如下:

Received: 21127 bytes (Downloaded: 1439932 bytes)  Expected: 1464162 bytes.
Progress =0.997860
Received: 21096 bytes (Downloaded: 1461028 bytes)  Expected: 1464162 bytes.
Progress =1.000000
Received: 3134 bytes (Downloaded: 1464162 bytes)  Expected: 1464162 bytes.
Background URL session <__NSURLBackgroundSession: 0x7fc5c357b560> finished events.

關(guān)于NSURLSessionConfiguration的配置策略你可以在這篇文章中找到胚吁。

1.AFNNetworking 2.0

你相信你一定知道AFNNetworking,不知道你還可以看看該作者的博文愁憔,所以我就不多說關(guān)于它的強(qiáng)大之處了腕扶,AFNetworking 提供了比NSURLSession更高層次的抽象,這篇文章主要總結(jié)AFNNetworking 2.0的幾個常用方法吨掌。

1).GET和POST請求

GET:

- (NSURLSessionDataTask *)GET:(NSString *)URLString
                   parameters:(id)parameters
                      success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                      failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure

POST:

- (NSURLSessionDataTask *)POST:(NSString *)URLString
                    parameters:(id)parameters
                       success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                       failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure

在實際的開發(fā)中半抱,我比較習(xí)慣把第三方的代碼進(jìn)行一層封裝脓恕,如下我們把GET和POST請求封裝起來:

//GET
+ (void)getWithPath:(NSString *)path params:(NSDictionary *)params success:(HttpSuccessBlock)success failure:(HttpFailureBlock)failure{
    [self requestWithPath:path params:params success:success failure:failure method:@"GET"];
}
//POST
+ (void)postWithPath:(NSString *)path params:(NSDictionary *)params success:(HttpSuccessBlock)success failure:(HttpFailureBlock)failure{
    [self requestWithPath:path params:params success:success failure:failure method:@"POST"];
}
typedef void (^HttpSuccessBlock)(id JSON);
typedef void (^HttpFailureBlock)(NSError *error);
...省略

+ (void)requestWithPath:(NSString *)path params:(NSDictionary *)params success:(HttpSuccessBlock)success failure:(HttpFailureBlock)failure method:(NSString *)method{
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:kBaseURL]];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain",@"application/json", @"text/json", @"text/javascript", @"text/html", nil];

    if ([method  isEqual: @"GET"]) {
        [manager GET:path parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
            success(responseObject);
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            NSLog(@"fail Get!!%@",error);
            failure(error);
        }];
    }else if ([method isEqual:@"POST"]){
        [manager POST:path parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
            NSLog(@"POST成功:%@",responseObject);
            success(responseObject);
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            NSLog(@"fail POST!!%@",error);
            failure(error);
        }];
    }
}

你有沒有注意到上面我設(shè)置了如下代碼:

manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain",@"application/json", @"text/json", @"text/javascript", @"text/html", nil];

因為AFNetworking的responseSerializer 屬性只能默認(rèn)只能處理特定的Content-Type,如果你想處理"text/html"等其它類型窿侈,你需要明確指定它的acceptableContentTypes炼幔。

2).多文件上傳

如下,這是我寫的第三方微博客戶端中多圖上傳的實例代碼:

[manager POST:@"2/statuses/upload.json"
           parameters:@{@"access_token": accseeToken,
                           @"status" : encodeStatus,
                           @"visible" : @(_intVisible),
                           @"lat" : @(_latitude),
                           @"long" : @(_longtitude)}
            constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
                NSMutableArray *images = [NSMutableArray arrayWithArray:weakSelf.images];
                for (id asset in images) {
                    NSData *data = nil;
                    if ([asset isKindOfClass:[UIImage class]]) {
                        data = UIImageJPEGRepresentation(asset, 0.4);
                    }
                    if ([asset isKindOfClass:ALAsset.class]) {
                        UIImage *original = [UIImage imageWithCGImage: [[asset defaultRepresentation] fullScreenImage]];
                        data = UIImageJPEGRepresentation(original, 0.4);
                    }
                    [formData appendPartWithFileData:data name:@"pic" fileName:@"pic.jpg" mimeType:@"multipart/form-data"];
                }
            } success:^(NSURLSessionDataTask *task, id responseObject) {
                NSLog(@"發(fā)送成功");
                [self back];
            } failure:^(NSURLSessionDataTask *task, NSError *error) {
                [self showFailHUD];
            }];

3).多線程操作

如果你需要開啟多個線程, 你需要使用AFHTTPRequestSerializer
史简,AFHTTPRequestOperation和NSOperationQueue

以下是AFNetworking的實例代碼

NSMutableArray *mutableOperations = [NSMutableArray array];
for (NSURL *fileURL in filesToUpload) {
    NSURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileURL:fileURL name:@"images[]" error:nil];
    }];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

    [mutableOperations addObject:operation];
}

NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:@[...] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
    NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations);
} completionBlock:^(NSArray *operations) {
    NSLog(@"All operations in batch complete");
}];
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];

3).網(wǎng)絡(luò)狀態(tài)檢查

網(wǎng)絡(luò)狀態(tài)檢查在早期都是通過蘋果官方的Reachability類進(jìn)行檢查乃秀,但是這個類本身存在一些問題,并且官方后來沒有再更新。我們可以直接使用AFNetworking框架檢測圆兵。不管使用官方提供的類還是第三方框架跺讯,用法都是類似的,通常是發(fā)送一個URL然后去檢測網(wǎng)絡(luò)狀態(tài)變化殉农,網(wǎng)絡(luò)改變后則調(diào)用相應(yīng)的網(wǎng)絡(luò)狀態(tài)改變方法诗充。如下:

-(void)alert:(NSString *)message{
    UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:@"System Info" message:message delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles: nil];
    [alertView show];
}

-(void)checkNetworkStatus{
    //創(chuàng)建一個用于測試的url
    NSURL *url=[NSURL URLWithString:@"http://www.apple.com"];
    AFHTTPRequestOperationManager *operationManager=[[AFHTTPRequestOperationManager alloc]initWithBaseURL:url];
    
    //根據(jù)不同的網(wǎng)絡(luò)狀態(tài)改變?nèi)プ鱿鄳?yīng)處理
    [operationManager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusReachableViaWWAN:
                [self alert:@"2G/3G/4G Connection."];
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                [self alert:@"WiFi Connection."];
                break;
            case AFNetworkReachabilityStatusNotReachable:
                [self alert:@"Network not found."];
                break;
            default:
                [self alert:@"Unknown."];
                break;
        }
    }];
    //開始監(jiān)控
    [operationManager.reachabilityManager startMonitoring];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末甜橱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子现恼,更是在濱河造成了極大的恐慌凯肋,老刑警劉巖肴颊,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秕重,死亡現(xiàn)場離奇詭異策治,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)创夜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門杭跪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人挥下,你說我怎么就攤上這事揍魂〗按祝” “怎么了棚瘟?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長喜最。 經(jīng)常有香客問我偎蘸,道長,這世上最難降的妖魔是什么瞬内? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任迷雪,我火速辦了婚禮,結(jié)果婚禮上虫蝶,老公的妹妹穿的比我還像新娘章咧。我一直安慰自己,他們只是感情好能真,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布赁严。 她就那樣靜靜地躺著扰柠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疼约。 梳的紋絲不亂的頭發(fā)上卤档,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機(jī)與錄音程剥,去河邊找鬼劝枣。 笑死,一個胖子當(dāng)著我的面吹牛织鲸,可吹牛的內(nèi)容都是我干的舔腾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼昙沦,長吁一口氣:“原來是場噩夢啊……” “哼琢唾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起盾饮,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤采桃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后丘损,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體普办,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年徘钥,在試婚紗的時候發(fā)現(xiàn)自己被綠了衔蹲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡呈础,死狀恐怖舆驶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情而钞,我是刑警寧澤沙廉,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站臼节,受9級特大地震影響撬陵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜网缝,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一巨税、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧粉臊,春花似錦草添、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽促王。三九已至,卻和暖如春而晒,著一層夾襖步出監(jiān)牢的瞬間蝇狼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工倡怎, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留迅耘,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓监署,卻偏偏與公主長得像颤专,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子钠乏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

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