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)(
typedefvoid(^FaileBlock)(NSError * error); // 請求錯誤返回的資料
typedefNS_ENUM(NSUInteger,WsqflyNetSessionMaskState) {
WsqflyNetSessionMaskStateNone = 0, // 沒有菊花
WsqflyNetSessionMaskStateCanTouch =
WsqflyNetSessionMaskStateNotTouch = 2// 有菊花單點選螢幕沒有效果
};
typedefNS_ENUM(NSUInteger,WsqflyNetSessionResponseType){
WsqflyNetSessionResponseTypeDATA = 0, // 返回後臺是什麼就是什麼DATA
WsqflyNetSessionResponseTypeJSON = 1// 返會序列化後的JSON資料
};
@interface
//單利
+ (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