1. 程式人生 > >iOS 原生NSURLSession 簡單的 GET、POST 請求

iOS 原生NSURLSession 簡單的 GET、POST 請求

//  WsqflyNetWorking.h

//  WSQNetWorkingSystem

//

//  Created by webapps on 16/12/28.

//  Copyright © 2016 webapps. All rights reserved.


#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>

typedefvoid(^SuccessBlock)(id response);                                 // 成功返回的資料

typedefvoid(^RequestHeadBlock)(

id response);                            // 請求頭返回的資料

typedefvoid(^FaileBlock)(NSError * error);                             // 請求錯誤返回的資料

typedefNS_ENUM(NSUInteger,WsqflyNetSessionMaskState) {

    WsqflyNetSessionMaskStateNone       =  0,                      // 沒有菊花

    WsqflyNetSessionMaskStateCanTouch   = 

1,                     // 有菊花並點選螢幕有效

    WsqflyNetSessionMaskStateNotTouch   =  2// 有菊花單點選螢幕沒有效果

};

typedefNS_ENUM(NSUInteger,WsqflyNetSessionResponseType){

    WsqflyNetSessionResponseTypeDATA    =  0,                // 返回後臺是什麼就是什麼DATA

    WsqflyNetSessionResponseTypeJSON    =  1// 返會序列化後的JSON資料

};

@interface

WsqflyNetSession : NSObject

//單利

+ (instancetype) wsqflyNetWorkingShare;

//判斷是否有網路

//+ (NSString *)connectedToNetwork;


/**GET短資料請求

 * urlString          網址

 * param              引數

 * state              顯示菊花的型別

 * backData           返回的資料是NSDATA還是JSON

 * successBlock       成功資料的block

 * faileBlock         失敗的block

 * requestHeadBlock   請求頭的資料的block

 */

- (void)get1:(NSString *)urlString param:(NSDictionary *)param maskState:(WsqflyNetSessionMaskState)state backData:(WsqflyNetSessionResponseType)backData success:(SuccessBlock)successBlock requestHead:(RequestHeadBlock)requestHeadBlock faile:(FaileBlock)faileBlock;

/**POST短資料請求

 * urlString           網址

 * param               引數

 * state               顯示菊花的型別

 * backData            返回的資料是NSDATA還是JSON

 * successBlock        成功資料的block

 * faileBlock          失敗的block

 * requestHeadBlock    請求頭的資料的block

 */

-(void)post:(NSString *)urlString bodyparam:(NSDictionary *)param maskState:(WsqflyNetSessionMaskState)state backData:(WsqflyNetSessionResponseType)backData success:(SuccessBlock)successBlock requestHead:(RequestHeadBlock)requestHeadBlock faile:(FaileBlock)faileBlock;

//

//  WsqflyNetWorking.m

//  WSQNetWorkingSystem

//

//  Created by webapps on 16/12/28.

//  Copyright © 2016 webapps. All rights reserved.

//

#import "WsqflyNetSession.h"

#import "RealReachability.h"

#define CONTECTTIME  30// 聯網時間

@interface WsqflyNetSession ()

@property (nonatomic,strong)UIActivityIndicatorView * wsqAView;

@property (nonatomic,assign)int maskCount;

@end

@implementation WsqflyNetSession

staticid _instance;

+ (instancetype)allocWithZone:(struct_NSZone *)zone

{

staticdispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

_instance = [superallocWithZone:zone];

    });

return_instance;

}

+ (instancetype)wsqflyNetWorkingShare

{

staticdispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

_instance = [[selfalloc] init];

    });

return_instance;

}

- (instancetype)init{

if (self = [superinit]) {

_wsqAView = [[UIActivityIndicatorViewalloc] initWithFrame:[UIScreenmainScreen].bounds];

_wsqAView.color = [UIColorblackColor];

    }

returnself;

}

#pragma mrak 判斷是否聯網

//+ (NSString *)connectedToNetwork

//{

//    NSString *netString;

//    ReachabilityStatus status = [GLobalRealReachability currentReachabilityStatus];

//    

//    switch (status) {

//        case -1:

//            netString = @"網路異常!";

//            break;

//        case 0:

//            netString = @"連線不到網路!";

//            break;

//        case 1:

//            netString = @"正在使用流量上網!";

//            break;

//        case 2:

//            netString = @"正在使用wifi上網!";

//            break;

//            

//        default:

//            break;

//    }

//    return netString;

//}

#pragma MARK-- GET

- (void)get1:(NSString *)urlString param:(NSDictionary *)param maskState:(WsqflyNetSessionMaskState)state backData:(WsqflyNetSessionResponseType)backData success:(SuccessBlock)successBlock requestHead:(RequestHeadBlock)requestHeadBlock faile:(FaileBlock)faileBlock{

NSURL *url;

NSString *string = [NSStringstring];

if (param) {//帶字典引數

        string = [selfnsdictionaryToNSStting:param];

//1. GET 請求,直接把請求引數跟在URL的後面以?(問號前是域名與/介面名)隔開,多個引數之間以&符號拼接

         url = [NSURLURLWithString:[selfurlConversionFromOriginalURL:[NSStringstringWithFormat:@"%@&%@",urlString,string]]];

    }else{

//1. GET 請求,直接把請求引數跟在URL的後面以?(問號前是域名與/介面名)隔開,多個引數之間以&符號拼接

        url = [NSURLURLWithString:[selfurlConversionFromOriginalURL:urlString]];

    }

//2. 建立請求物件內部默認了已經包含了請求頭和請求方法(GET)的物件

NSMutableURLRequest *request = [[NSMutableURLRequestalloc] initWithURL:urlcachePolicy:NSURLRequestUseProtocolCachePolicytimeoutInterval:CONTECTTIME];

/*   設定請求頭  */

//    [request setValue:@"92b5787ecd17417b718a2aaedc7e6ce8" forHTTPHeaderField:@"apix-key"];

//4. 根據會話物件建立一個task任務(傳送請求)

    [selfstartNSURLSessionDataTask:requestmaskState:state responType:backDatasuccess:successBlock headfiles:requestHeadBlock fail:faileBlock];

}

#pragma MARK-- POST

-(void)post:(NSString *)urlString bodyparam:(NSDictionary *)param maskState:(WsqflyNetSessionMaskState)state backData:(WsqflyNetSessionResponseType)backData success:(SuccessBlock)successBlock requestHead:(RequestHeadBlock)requestHeadBlock faile:(FaileBlock)faileBlock{

//POST請求需要修改請求方法為POST,並把引數轉換為二進位制資料設定為請求體

//1.url

NSURL *url = [NSURLURLWithString:[selfurlConversionFromOriginalURL:urlString]];

//2.建立可變的請求物件

NSMutableURLRequest *request = [[NSMutableURLRequestalloc] initWithURL:urlcachePolicy:NSURLRequestUseProtocolCachePolicytimeoutInterval:CONTECTTIME];

/*   設定請求頭  */

//    [request setValue:@"92b5787ecd17417b718a2aaedc7e6ce8" forHTTPHeaderField:@"apix-key"];

//4.修改請求方法為POST

    request.HTTPMethod =@"POST";

//有引數請求題

if (param) {

//5.設定請求體

NSString *string = [selfnsdictionaryToNSStting:param];

        request.HTTPBody = [stringdataUsingEncoding:NSUTF8StringEncoding];

    }

//6.根據會話物件建立一個Task(傳送請求)

    [selfstartNSURLSessionDataTask:requestmaskState:state responType:backDatasuccess:successBlock headfiles:requestHeadBlock fail:faileBlock];

}

#pragma MARK-- 根據會話物件建立一個Task(傳送請求)

- (void)startNSURLSessionDataTask:(NSMutableURLRequest *)request  maskState:(WsqflyNetSessionMaskState)state responType:(WsqflyNetSessionResponseType)responType success:(SuccessBlock)respone headfiles:(RequestHeadBlock)headfiles fail:(FaileBlock)fail{

//3.建立會話物件

NSURLSession *session = [NSURLSessionsharedSession];

/*

第一個引數:請求物件

第二個引數:completionHandler回撥(請求完成【成功|失敗】的回撥)

     data:響應體資訊(期望的資料)

     response:響應頭資訊,主要是對伺服器端的描述

     error:錯誤資訊,如果請求失敗,則error有值

     */

NSURLSessionDataTask *dataTask = [sessiondataTaskWithRequest:requestcompletionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError * _Nullable error) {

        [selfstopAnimation:state];

NSString *result = [[NSStringalloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"result:%@",result);

// 解析伺服器返回的資料(返回的資料為JSON格式,因此使用NSJNOSerialization進行反序列化)

id dict = [NSJSONSerializationJSONObjectWithData:data options:NSJSONReadingMutableLeaveserror:nil];

NSLog(@"response%@",response);

NSHTTPURLResponse * da =(NSHTTPURLResponse *)response;

NSDictionary *allheadsFiles = da.allHeaderFields;

NSLog(@"allheadsFiles:%@",allheadsFiles[@"Content-Type"]);

//8.解析資料

if (!error) {

if (responType ==WsqflyNetSessionResponseTypeJSON) {//返回JSON

                respone(dict);

            }else{

                   respone(data);//返回二進位制

            }

        }else{

            fail(error);

NSLog(@"網路請求失敗");

        }

if (response) {

            headfiles(allheadsFiles);

        }

    }];

//7.執行任務

    [selfshowAnimation:state];

    [dataTask resume];

}

#pragma MARK -- 菊花

// 新增菊花

- (void)showAnimation:(WsqflyNetSessionMaskState)maskType {

if (maskType !=WsqflyNetSessionMaskStateNone) {  // 有菊花動畫

dispatch_async(dispatch_get_main_queue(), ^{

            [UIApplicationsharedApplication].networkActivityIndicatorVisible =true;

            [[UIApplicationsharedApplication].keyWindowaddSubview:_wsqAView];

_wsqAView.hidden =NO;

            [_wsqAViewstartAnimating];

_wsqAView.userInteractionEnabled = (maskType ==WsqflyNetSessionMaskStateNotTouch ?YES : NO);

_maskCount++;

        });

    }

}

// 移除菊花

- (void)stopAnimation:(WsqflyNetSessionMaskState)maskType {

if (maskType !=WsqflyNetSessionMaskStateNone) {

dispatch_async(dispatch_get_main_queue(), ^{

_maskCount--;

if (_maskCount <=0) {

                [UIApplicationsharedApplication].networkActivityIndicatorVisible =false;

                [_wsqAViewstopAnimating];

_wsqAView.hidden =YES;

                [_wsqAViewremoveFromSuperview];

            }

        });

    }

}

#pragma MARK -- 把字典拼成字串

- (NSString *) nsdictionaryToNSStting:(NSDictionary *)param{

NSMutableString *string = [NSMutableStringstring];

//便利字典把鍵值平起來

    [param enumerateKeysAndObjectsUsingBlock:^(id_Nonnull key, id_Nonnull obj, BOOL *_Nonnull stop) {

        [string appendFormat:@"%@:",key];

        [string appendFormat:@"%@",obj];

        [string appendFormat:@"%@",@"&"];

    }];

// 去掉最後一個&

NSRange rangeLast = [stringrangeOfString:@"&"options:NSBackwardsSearch];

if (rangeLast.length !=0) {

        [string deleteCharactersInRange:rangeLast];

    }

NSLog(@"string:%@",string);

NSRange range =NSMakeRange(0, [stringlength]);

    [string replaceOccurrencesOfString:@":"withString:@"="options:NSCaseInsensitiveSearchrange:range];

NSLog(@"string:%@",string);

return string;

}

// 如果URL有中文,轉換成百分號

- (NSString *)urlConversionFromOriginalURL:(NSString *)originalURL {

if ([[UIDevicecurrentDevice].systemVersionfloatValue] < 9.0) {

return [originalURLstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];// iOS 9.0以下

    }

return [originalURLstringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSetURLQueryAllowedCharacterSet]];

}

#pragma mark NSURLSession Delegate

/* 收到身份驗證 ssl */

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition,NSURLCredential * _Nullable))completionHandler {

NSLog(@"didReceiveChallenge %@", challenge.protectionSpace);

NSLog(@"呼叫了最外層");

// 1.判斷伺服器返回的證書型別,是否是伺服器信任

if ([challenge.protectionSpace.authenticationMethodisEqualToString:NSURLAuthenticationMethodServerTrust]) {       NSLog(@"呼叫了裡面這一層是伺服器信任的證書");

/*  NSURLSessionAuthChallengeUseCredential = 0,                    使用證書         NSURLSessionAuthChallengePerformDefaultHandling = 1,           忽略證書(預設的處理方式)         NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2,     忽略書證,並取消這次請求         NSURLSessionAuthChallengeRejectProtectionSpace = 3,           拒絕當前這一次,下一次再詢問

         */

NSURLCredential *card = [[NSURLCredentialalloc]initWithTrust:challenge.protectionSpace.serverTrust];

        completionHandler(NSURLSessionAuthChallengeUseCredential , card);

    }

}

@end