寫在前面:對(duì)于移動(dòng)端開發(fā)來說,無論iOS,Android,抑或是H5開發(fā),所謂的開發(fā)核心之一就是從服務(wù)端接收數(shù)據(jù),前端負(fù)責(zé)展示,所以,當(dāng)然還有各種邏輯的實(shí)現(xiàn),但是呢,一個(gè)完善的APP肯定是少不了與服務(wù)端交互的,所以一個(gè)網(wǎng)絡(luò)請(qǐng)求類的封裝好用與否直接關(guān)系到一個(gè)項(xiàng)目的開發(fā)效率以及后期的維護(hù),本人也接手過那種沒有請(qǐng)求類的項(xiàng)目呢,每個(gè)請(qǐng)求寫了一堆代碼,用的全部是ASI,,然后需要更改為AFN的時(shí)候,哇,簡直無敵了,然后Command+F都用不上,只能一處處找,找的自己都不知道時(shí)間了,真的相當(dāng)折磨,受過這個(gè)折磨的童鞋肯定能夠體會(huì)這種痛苦,有種刪除項(xiàng)目,拍屁股走人的邪惡想法,但是呢,畢竟咱的職業(yè)素養(yǎng)還在,所以就耐心的享受這折磨了.廢話不多說,相信每個(gè)開發(fā)的童鞋都能知道一個(gè)好的網(wǎng)絡(luò)請(qǐng)求類帶給我們的便捷之處.
** 1.Swift3.0**
不用過多介紹什么,Swift是蘋果主推的開發(fā)語言,老司機(jī)都知道原來是OC,Swift語言筆者前天花了一下午+一晚上的時(shí)間學(xué)習(xí)了下,確實(shí)很簡潔,開發(fā)速度確實(shí)很快,風(fēng)格類似于(JS+Python)我比較喜歡的是Swift中的泛型,泛型這個(gè)東西Java中有,當(dāng)初寫Java的時(shí)候泛型真的讓我方便了很多很多,所以在進(jìn)行iOS開發(fā)的時(shí)候一直琢磨著有沒有泛型這個(gè)東西,可是呢,都知道沒有...最近安卓新出的kotlin語言,跟Swift也是大同小異吧.
** 2.AFN**
AFN是一套iOS網(wǎng)絡(luò)請(qǐng)求框架,用OC語言編寫(我記得原來有Swift語言編寫的,但是去GitHub上找的時(shí)候沒有找到)這個(gè)框架現(xiàn)在幾乎所有的iOS項(xiàng)目都在用吧,確實(shí)很好用,當(dāng)然不缺乏大牛公司自己封裝的,當(dāng)然也可能有老項(xiàng)目還在用ASI(曾經(jīng)火了好長時(shí)間,但是現(xiàn)在沒人用了,WHy?因?yàn)樽髡卟桓铝?..可悲不)
** 3.MJExtention**
MJExtention是李明杰大神的一套框架,主要用來字典轉(zhuǎn)模型,這個(gè)框架的好用程度本人給100分,當(dāng)然還有別的功能,其他的童鞋們慢慢去挖掘吧.即便你的對(duì)象里包含對(duì)象數(shù)組,它也可以幫你全部轉(zhuǎn)換的哦,有不懂的或者有興趣的可以直接去GitHub上下載學(xué)習(xí)一下,或者給我留言也可以哦.
4.封裝思想
我也相信這些封裝思想應(yīng)該很多人都知道了,思想就像風(fēng)暴一樣,瞬間可以席卷全球,真是個(gè)神奇的東西,當(dāng)然我的這個(gè)也是來源于網(wǎng)絡(luò)上大神的分享.
AFN的源碼我看了一遍,我們可以直接用AFHTTPSessionManager,有興趣的童鞋可以研究下AFN的源碼,然后我的想法是繼承AFHTTPSessionManager創(chuàng)建一個(gè)RequsetManager類,(當(dāng)然第一版我用的是裝飾模式,是在RequsetManager中裝飾一個(gè)AFHTTPSessionManager對(duì)象,當(dāng)然兩種方法各有各的優(yōu)點(diǎn),直接繼承可能調(diào)用方法上更加簡潔一點(diǎn),然后也會(huì)減少一個(gè)對(duì)象的使用...)提供一個(gè)RequsetManager單例,然后創(chuàng)建一個(gè)NetworkService類,為所有的請(qǐng)求提供服務(wù),在這個(gè)里面使用包裝RequsetManager,使用RequsetManager下載數(shù)據(jù),在NetworkService中提供對(duì)數(shù)據(jù)的解密,緩存(當(dāng)然我沒有去實(shí)現(xiàn)緩存的功能),以及對(duì)數(shù)據(jù)的解析轉(zhuǎn)換(MJExtention在這兒真的起了很大的作用--在此轉(zhuǎn)換數(shù)據(jù)的時(shí)候我們需要知道將json數(shù)據(jù)轉(zhuǎn)換為什么樣的對(duì)象,在OC版本中實(shí)現(xiàn)的時(shí)候我們是將要轉(zhuǎn)換對(duì)象的Class當(dāng)做參數(shù)傳了過去,但是返回的結(jié)果是id的,我們用的時(shí)候需要進(jìn)行強(qiáng)轉(zhuǎn),但是在Swift中我們有了泛型,所以這一步就簡潔了很多,具體的祥看代碼,后面會(huì)同樣奉上OC版本的封裝).
5.OC版本
RequsetManager:僅僅實(shí)現(xiàn)了Post和GET方法,聲明了成功和失敗的Block回調(diào),一個(gè)重新載入請(qǐng)求頭的,當(dāng)然大部分是沒有用的,另外一個(gè)是獲取單利的,但是,所有的方法均是靜態(tài)方法,獲取單利是可以在外部單獨(dú)設(shè)置請(qǐng)求頭
#import "AFHTTPSessionManager.h"
typedef void (^requestSuccessBlock)(id responseObj);
typedef void (^requestFailureBlock) (NSError *error);
@interface RequsetManager : AFHTTPSessionManager
+ (instancetype)sharedRequestManager;
+ (void)AFN_ReloadHeaderAuth;
+ (void)AFN_GetRequest:(NSString *)url params:(NSDictionary *)params success:(requestSuccessBlock)successHandler failure:(requestFailureBlock)failureHandler;
+ (void)AFN_PostRequest:(NSString *)url params:(NSDictionary *)params success:(requestSuccessBlock)successHandler failure:(requestFailureBlock)failureHandler;
@end
實(shí)現(xiàn)如下:
#import "RequsetManager.h"
@interface RequsetManager()
@end
@implementation RequsetManager
+ (instancetype)sharedRequestManager{
static dispatch_once_t onceToken;
static RequsetManager * manager = nil;
dispatch_once(&onceToken, ^{
manager = [[self alloc]init];
manager.requestSerializer.timeoutInterval = 60.0f;
[manager.requestSerializer setValue:@"" forHTTPHeaderField:@"jwttoken"];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
});
return manager;
}
+ (void)AFN_ReloadHeaderAuth{
[[[self sharedRequestManager] requestSerializer] setValue:@"" forHTTPHeaderField:@"jwttoken"];
}
+ (void)AFN_GetRequest:(NSString *)url params:(NSDictionary *)params success:(requestSuccessBlock)successHandler failure:(requestFailureBlock)failureHandler{
[[self sharedRequestManager] GET:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
successHandler(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
failureHandler(error);
}];
}
+ (void)AFN_PostRequest:(NSString *)url params:(NSDictionary *)params success:(requestSuccessBlock)successHandler failure:(requestFailureBlock)failureHandler{
[[self sharedRequestManager] POST:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
successHandler(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
failureHandler(error);
}];
}
@end
RequestService:僅僅封裝了返回結(jié)果為JSON的,其實(shí)有XMLDictionary可以將XML轉(zhuǎn)換為JSON的,有興趣的可以從后面我的GitHub上下載demo ,里面包含了這個(gè)類,當(dāng)然也可以直接從GitHub上搜索
#import <Foundation/Foundation.h>
typedef void (^responseResultBlock)(id dataObj, NSError *error);
@interface RequestService : NSObject
/**
重新載入請(qǐng)求頭
*/
+ (void)reloadAFNHeaderAuth;
/**
利用AFN請(qǐng)求獲取JSON返回 --- GET請(qǐng)求
@param url 請(qǐng)求地址
@param param 請(qǐng)求參數(shù)
@param modelClass 請(qǐng)求返回所需要轉(zhuǎn)換的模型類
@param responseBlock 請(qǐng)求成功|失敗回調(diào)
*/
+ (void)AFN_JSONResponseGetWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock) responseBlock;
/**
利用AFN請(qǐng)求獲取JSON返回 --- POST請(qǐng)求
@param url 請(qǐng)求地址
@param param 請(qǐng)求參數(shù)
@param modelClass 請(qǐng)求返回所需要轉(zhuǎn)換的模型類
@param responseBlock 請(qǐng)求成功|失敗回調(diào)
*/
+ (void)AFN_JSONResponsePostWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock)responseBlock;
/**
請(qǐng)求返回結(jié)果轉(zhuǎn)換為模型方法 -- 此方法不需要關(guān)注,如果有Service繼承此類,可以重寫該方法進(jìn)行數(shù)據(jù)處理
@param responseObj 返回結(jié)果
@param modelClass 模型類
@return 轉(zhuǎn)換成功的模型
*/
+ (id)modelTransformationWithResponseObj:(id)responseObj modelClass:(Class)modelClass;
@end
具體實(shí)現(xiàn)如下:
#import "RequestService.h"
#import "RequsetManager.h"
#import "MJExtension.h"
static id dataObj;
@implementation RequestService
+ (void)reloadAFNHeaderAuth{
[RequsetManager AFN_ReloadHeaderAuth];
}
+ (void)AFN_JSONResponseGetWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock) responseBlock{
[RequsetManager AFN_GetRequest:url params:param success:^(id responseObj) {
dataObj = [self modelTransformationWithResponseObj:responseObj modelClass:modelClass];
responseBlock(dataObj,nil);
} failure:^(NSError *error) {
responseBlock(nil,error);
}];
}
+ (void)AFN_JSONResponsePostWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock)responseBlock{
[RequsetManager AFN_PostRequest:url params:param success:^(id responseObj) {
dataObj = [self modelTransformationWithResponseObj:responseObj modelClass:modelClass];
responseBlock(dataObj,nil);
} failure:^(NSError *error) {
responseBlock(nil,error);
}];
}
+ (id)convertJson:(NSString *)jsonStr
{
if (!jsonStr) {
return nil;
}
NSError * error;
return [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableLeaves error:&error];
}
/**
解密
@param response 網(wǎng)絡(luò)數(shù)據(jù)
@return 解密結(jié)果
*/
+ (NSString *)decreptResponse:(NSString *)response{
return response;
}
+ (id)modelTransformationWithResponseObj:(id)responseObj modelClass:(Class)modelClass{
NSString *response = [[NSString alloc] initWithData:(NSData *)responseObj encoding:NSUTF8StringEncoding];
response = [self decreptResponse:response];
id tmp = [self convertJson:response];
if ([tmp isKindOfClass:[NSArray class]]) {
return [modelClass mj_objectArrayWithKeyValuesArray:responseObj];
}else if([tmp isKindOfClass:[NSDictionary class]]){
return [modelClass mj_objectWithKeyValues:responseObj];
}
return nil;
}
@end
6.Swift版本
import Foundation
/// 請(qǐng)求工具類
class NetworkService{
/// Get 請(qǐng)求
///
/// - Parameters:
/// - url: 請(qǐng)求地址
/// - params: 請(qǐng)求參數(shù)
/// - complete: 請(qǐng)求回調(diào) -- 回傳結(jié)果為對(duì)象
static func GetRequest<T:NSObject>(url:String,
params:[String:AnyObject]?,
complete:@escaping (_ dataModel:T?,_ error:Error?)->()){
RequsetManager.getRequest(url: url, params: params, success: { (result) in
self.transformModel(result: result, complete: { (resultObj:T?,resultArr:[T]?) in
complete(resultObj,nil)
})
}) { (error) in
complete(nil,error)
}
}
/// Get請(qǐng)求
///
/// - Parameters:
/// - url: 請(qǐng)求地址
/// - params: 請(qǐng)求參數(shù)
/// - complete: 請(qǐng)求完成回調(diào) -- 回傳結(jié)果為對(duì)象數(shù)組
static func GetRequest<T:NSObject>(url:String,
params:[String:AnyObject]?,
complete:@escaping (_ dataModelArray:[T]?,_ error:Error?)->()){
RequsetManager.getRequest(url: url, params: params, success: { (result) in
self.transformModel(result: result, complete: { (resultObj:T?,resultArr:[T]?) in
complete(resultArr,nil)
})
}) { (error) in
complete(nil,error)
}
}
/// Post 請(qǐng)求
///
/// - Parameters:
/// - url: 請(qǐng)求地址
/// - params: 請(qǐng)求參數(shù)
/// - complete: 請(qǐng)求回調(diào) -- 回傳結(jié)果為對(duì)象
static func PostRequest<T:NSObject>(url:String,
params:[String:AnyObject]?,
complete:@escaping (_ dataModel:T?,_ error:Error?)->()){
RequsetManager.postRequest(url: url, params: params, success: { (result) in
self.transformModel(result: result, complete: { (resultObj:T?,resultArr:[T]?) in
complete(resultObj,nil)
})
}) { (error) in
complete(nil,error)
}
}
/// Post請(qǐng)求
///
/// - Parameters:
/// - url: 請(qǐng)求地址
/// - params: 請(qǐng)求參數(shù)
/// - complete: 請(qǐng)求完成回調(diào) -- 回傳結(jié)果為對(duì)象數(shù)組
static func PostRequest<T:NSObject>(url:String,
params:[String:AnyObject]?,
complete:@escaping (_ dataModelArray:[T]?,_ error:Error?)->()){
RequsetManager.postRequest(url: url, params: params, success: { (result) in
self.transformModel(result: result, complete: { (resultObj:T?,resultArr:[T]?) in
complete(resultArr,nil)
})
}) { (error) in
complete(nil,error)
}
}
/// 轉(zhuǎn)換方法
///
/// - Parameters:
/// - result: 網(wǎng)絡(luò)返回?cái)?shù)據(jù)
/// - complete: 轉(zhuǎn)換完成回調(diào)
static func transformModel<T:NSObject>(result:Any?,
complete:@escaping (_ result:T?,_ resultArray:[T]?)->()){
let jsonStr = self.converNetData(result: result as Any)
let obj = T.mj_object(withKeyValues: jsonStr)
var objArr = [T]()
if T.mj_objectArray(withKeyValuesArray: jsonStr) != nil {
for item in T.mj_objectArray(withKeyValuesArray: jsonStr) {
objArr.append(item as! T)
}
}
complete(obj,objArr)
}
/// 轉(zhuǎn)換網(wǎng)絡(luò)數(shù)據(jù)
///
/// - Parameter result: 網(wǎng)絡(luò)數(shù)據(jù)
/// - Returns: 返回結(jié)果
static func converNetData(result:Any) -> String{
let respose = String.init(data: result as! Data, encoding: String.Encoding.utf8)
return self.decreptRespose(respose: respose)
}
/// 解密
///
/// - Parameter respose: 網(wǎng)絡(luò)數(shù)據(jù)
/// - Returns: 解密結(jié)果
static func decreptRespose(respose:String?) -> String{
//自己實(shí)現(xiàn)解密
return respose ?? "{}"
}
}
/// 請(qǐng)求管理
class RequsetManager :AFHTTPSessionManager {
/// 初始化RequsetManager單利
static let sharedRequestManager:RequsetManager = {
let instance = RequsetManager()
instance.requestSerializer.timeoutInterval = 60.0
//自定義設(shè)置請(qǐng)求頭
// instance.requestSerializer.setValue(<#T##value: String?##String?#>, forHTTPHeaderField: <#T##String#>)
instance.responseSerializer = AFHTTPResponseSerializer()
return instance
}()
/// GET請(qǐng)求
///
/// - Parameters:
/// - url: 請(qǐng)求地址
/// - params: 請(qǐng)求參數(shù)
/// - success: 請(qǐng)求成功回調(diào)
/// - failure: 請(qǐng)求失敗回調(diào)
static func getRequest(url:String,
params:[String:AnyObject]?,
success:@escaping (_ responseData:Any?)->()?,
failure:@escaping (_ error:Error)->()?){
RequsetManager.sharedRequestManager.get(url, parameters: params, progress: nil, success: {
(task:URLSessionDataTask,result:Any?) in
success(result)
}) { (task:URLSessionDataTask?, error:Error) in
failure(error)
}
}
/// POST請(qǐng)求
///
/// - Parameters:
/// - url: 請(qǐng)求地址
/// - params: 請(qǐng)求參數(shù)
/// - success: 請(qǐng)求成功回調(diào)
/// - failure: 請(qǐng)求失敗回調(diào)
static func postRequest(url:String,
params:[String:AnyObject]?,
success:@escaping (_ responseData:Any?)->()?,
failure:@escaping (_ error:Error)->()?){
RequsetManager.sharedRequestManager.post(url, parameters: params, progress: nil, success: {
(task:URLSessionDataTask,result:Any?) in
success(result)
}) { (task:URLSessionDataTask?, error:Error) in
failure(error)
}
}
}
7.對(duì)比--使用--分析
Swift版本其實(shí)就是對(duì)OC版本的一個(gè)更改在RequsetManager層次幾乎是一樣的,在Service層,OC版本需要在使用的時(shí)候?qū)⑺D(zhuǎn)換的對(duì)象的Class當(dāng)做參數(shù)傳過來,而在Swift版本中,僅僅需要在閉包中用泛型就可以,無需再需要傳遞對(duì)象的類
在使用上,OC版本回調(diào)回去的是一個(gè)id對(duì)象,無論是對(duì)象數(shù)組抑或是對(duì)象,都需要強(qiáng)制轉(zhuǎn)換后使用,而在Swift版本中,我用了多態(tài)的性質(zhì),根據(jù)使用時(shí)傳遞的閉包不同,返回的結(jié)果也不同,結(jié)果是對(duì)象的和結(jié)果是對(duì)象數(shù)組的,可以分別選擇調(diào)用相對(duì)應(yīng)的方法.
使用
返回結(jié)果是對(duì)象的OC版本:
- (void)test1{
[RequestService AFN_JSONResponseGetWithUrl:@"http://192.168.1.107:8080/SkeeterTask/test/login" param:nil modelClass:[TestModel class] responseBlock:^(id dataObj, NSError *error) {
if (error) {
return ;
}
//使用上需要將id類型的dataObj進(jìn)行強(qiáng)轉(zhuǎn)...
NSLog(@"結(jié)果為對(duì)象---%@",((TestModel *)dataObj).message);
}];
}
返回結(jié)果是對(duì)象數(shù)組的OC版本:
[RequestService AFN_JSONResponseGetWithUrl:@"http://192.168.1.107:8080/SkeeterTask/test/login2" param:nil modelClass:[TestModel class] responseBlock:^(id dataObj, NSError *error) {
if (error) {
return ;
}
//此時(shí)沒必要強(qiáng)制轉(zhuǎn)換,如果網(wǎng)絡(luò)數(shù)據(jù)返回的是數(shù)組,得到的dataObj肯定是數(shù)組
而且里面的對(duì)象肯定是傳的modelClass對(duì)象
for (TestModel * mode in dataObj) {
NSLog(@"結(jié)果為對(duì)象數(shù)組--%@",mode.message);
}
}];
返回結(jié)果是對(duì)象的Swift版本
NetworkService .GetRequest(url: "http://192.168.1.107:8080/SkeeterTask/test/login", params: nil) { (model:TestModel?, error:Error?) in
if error != nil {
print("Error")
return
}
//調(diào)用方法的時(shí)候TestModel是當(dāng)做泛型傳遞過去的,所以回調(diào)的model
是可以直接來使用的
print("結(jié)果為對(duì)象--->\(model?.message ?? "NoMessage")")
}
返回結(jié)果是對(duì)象數(shù)組的Swift版本
NetworkService.GetRequest(url: "http://192.168.1.107:8080/SkeeterTask/test/login2", params: nil) { (modelArr:[TestModel]?, error:Error?) in
if error != nil{
print("Error")
return
}
//運(yùn)用傳遞的閉包不同,返回的modelArr的泛型為TestModel
所以返回過來之后可以直接使用了
if let arr = modelArr{
for item in arr{
print("結(jié)果為對(duì)象數(shù)組--->\(item.message ?? "NoMessage")")
}
}
}
分析,這兩中其實(shí)思想是一樣的,只不過Swift版本因?yàn)槭褂昧朔盒?所以在使用的時(shí)候更加清晰,而且也不需要將所要轉(zhuǎn)換的對(duì)象類當(dāng)做參數(shù)進(jìn)行傳遞,而且使用了多態(tài),根據(jù)返回的結(jié)果不同分別傳遞不同的閉包,而OC版本,始終都是那一個(gè)方法,需要對(duì)返回的結(jié)果進(jìn)行強(qiáng)制轉(zhuǎn)換,所以使用起來沒有那么的一目了然,大致就是這樣,希望我這個(gè)可以拋磚引玉,有好的想法的童鞋可以給我留言交流,共同提高
8.寫在最后
最后提醒一下,我請(qǐng)求的地址是我使用Java寫的本地的一個(gè)服務(wù),小伙伴們?cè)谑褂玫臅r(shí)候可要進(jìn)行相對(duì)應(yīng)的更改哦,最后奉上我測(cè)試的結(jié)果截圖,有什么不足呢,可以給我留言溝通共同提高哦.謝謝


10.最后的最后,奉上完整的Demo地址(XML轉(zhuǎn)JSON的類在OC源碼中)