寫在前面:對于移動端開發(fā)來說,無論iOS,Android,抑或是H5開發(fā),所謂的開發(fā)核心之一就是從服務端接收數(shù)據(jù),前端負責展示,所以,當然還有各種邏輯的實現(xiàn),但是呢,一個完善的APP肯定是少不了與服務端交互的,所以一個網(wǎng)絡請求類的封裝好用與否直接關系到一個項目的開發(fā)效率以及后期的維護,本人也接手過那種沒有請求類的項目呢,每個請求寫了一堆代碼,用的全部是ASI,,然后需要更改為AFN的時候,哇,簡直無敵了,然后Command+F都用不上,只能一處處找,找的自己都不知道時間了,真的相當折磨,受過這個折磨的童鞋肯定能夠體會這種痛苦,有種刪除項目,拍屁股走人的邪惡想法,但是呢,畢竟咱的職業(yè)素養(yǎng)還在,所以就耐心的享受這折磨了.廢話不多說,相信每個開發(fā)的童鞋都能知道一個好的網(wǎng)絡請求類帶給我們的便捷之處.
** 1.Swift3.0**
不用過多介紹什么,Swift是蘋果主推的開發(fā)語言,老司機都知道原來是OC,Swift語言筆者前天花了一下午+一晚上的時間學習了下,確實很簡潔,開發(fā)速度確實很快,風格類似于(JS+Python)我比較喜歡的是Swift中的泛型,泛型這個東西Java中有,當初寫Java的時候泛型真的讓我方便了很多很多,所以在進行iOS開發(fā)的時候一直琢磨著有沒有泛型這個東西,可是呢,都知道沒有...最近安卓新出的kotlin語言,跟Swift也是大同小異吧.
** 2.AFN**
AFN是一套iOS網(wǎng)絡請求框架,用OC語言編寫(我記得原來有Swift語言編寫的,但是去GitHub上找的時候沒有找到)這個框架現(xiàn)在幾乎所有的iOS項目都在用吧,確實很好用,當然不缺乏大牛公司自己封裝的,當然也可能有老項目還在用ASI(曾經(jīng)火了好長時間,但是現(xiàn)在沒人用了,WHy?因為作者不更新了...可悲不)
** 3.MJExtention**
MJExtention是李明杰大神的一套框架,主要用來字典轉模型,這個框架的好用程度本人給100分,當然還有別的功能,其他的童鞋們慢慢去挖掘吧.即便你的對象里包含對象數(shù)組,它也可以幫你全部轉換的哦,有不懂的或者有興趣的可以直接去GitHub上下載學習一下,或者給我留言也可以哦.
4.封裝思想
我也相信這些封裝思想應該很多人都知道了,思想就像風暴一樣,瞬間可以席卷全球,真是個神奇的東西,當然我的這個也是來源于網(wǎng)絡上大神的分享.
AFN的源碼我看了一遍,我們可以直接用AFHTTPSessionManager,有興趣的童鞋可以研究下AFN的源碼,然后我的想法是繼承AFHTTPSessionManager創(chuàng)建一個RequsetManager類,(當然第一版我用的是裝飾模式,是在RequsetManager中裝飾一個AFHTTPSessionManager對象,當然兩種方法各有各的優(yōu)點,直接繼承可能調用方法上更加簡潔一點,然后也會減少一個對象的使用...)提供一個RequsetManager單例,然后創(chuàng)建一個NetworkService類,為所有的請求提供服務,在這個里面使用包裝RequsetManager,使用RequsetManager下載數(shù)據(jù),在NetworkService中提供對數(shù)據(jù)的解密,緩存(當然我沒有去實現(xiàn)緩存的功能),以及對數(shù)據(jù)的解析轉換(MJExtention在這兒真的起了很大的作用--在此轉換數(shù)據(jù)的時候我們需要知道將json數(shù)據(jù)轉換為什么樣的對象,在OC版本中實現(xiàn)的時候我們是將要轉換對象的Class當做參數(shù)傳了過去,但是返回的結果是id的,我們用的時候需要進行強轉,但是在Swift中我們有了泛型,所以這一步就簡潔了很多,具體的祥看代碼,后面會同樣奉上OC版本的封裝).
5.OC版本
RequsetManager:僅僅實現(xiàn)了Post和GET方法,聲明了成功和失敗的Block回調,一個重新載入請求頭的,當然大部分是沒有用的,另外一個是獲取單利的,但是,所有的方法均是靜態(tài)方法,獲取單利是可以在外部單獨設置請求頭
#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
實現(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:僅僅封裝了返回結果為JSON的,其實有XMLDictionary可以將XML轉換為JSON的,有興趣的可以從后面我的GitHub上下載demo ,里面包含了這個類,當然也可以直接從GitHub上搜索
#import <Foundation/Foundation.h>
typedef void (^responseResultBlock)(id dataObj, NSError *error);
@interface RequestService : NSObject
/**
重新載入請求頭
*/
+ (void)reloadAFNHeaderAuth;
/**
利用AFN請求獲取JSON返回 --- GET請求
@param url 請求地址
@param param 請求參數(shù)
@param modelClass 請求返回所需要轉換的模型類
@param responseBlock 請求成功|失敗回調
*/
+ (void)AFN_JSONResponseGetWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock) responseBlock;
/**
利用AFN請求獲取JSON返回 --- POST請求
@param url 請求地址
@param param 請求參數(shù)
@param modelClass 請求返回所需要轉換的模型類
@param responseBlock 請求成功|失敗回調
*/
+ (void)AFN_JSONResponsePostWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock)responseBlock;
/**
請求返回結果轉換為模型方法 -- 此方法不需要關注,如果有Service繼承此類,可以重寫該方法進行數(shù)據(jù)處理
@param responseObj 返回結果
@param modelClass 模型類
@return 轉換成功的模型
*/
+ (id)modelTransformationWithResponseObj:(id)responseObj modelClass:(Class)modelClass;
@end
具體實現(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)絡數(shù)據(jù)
@return 解密結果
*/
+ (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
/// 請求工具類
class NetworkService{
/// Get 請求
///
/// - Parameters:
/// - url: 請求地址
/// - params: 請求參數(shù)
/// - complete: 請求回調 -- 回傳結果為對象
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請求
///
/// - Parameters:
/// - url: 請求地址
/// - params: 請求參數(shù)
/// - complete: 請求完成回調 -- 回傳結果為對象數(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 請求
///
/// - Parameters:
/// - url: 請求地址
/// - params: 請求參數(shù)
/// - complete: 請求回調 -- 回傳結果為對象
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請求
///
/// - Parameters:
/// - url: 請求地址
/// - params: 請求參數(shù)
/// - complete: 請求完成回調 -- 回傳結果為對象數(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)
}
}
/// 轉換方法
///
/// - Parameters:
/// - result: 網(wǎng)絡返回數(shù)據(jù)
/// - complete: 轉換完成回調
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)
}
/// 轉換網(wǎng)絡數(shù)據(jù)
///
/// - Parameter result: 網(wǎng)絡數(shù)據(jù)
/// - Returns: 返回結果
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)絡數(shù)據(jù)
/// - Returns: 解密結果
static func decreptRespose(respose:String?) -> String{
//自己實現(xiàn)解密
return respose ?? "{}"
}
}
/// 請求管理
class RequsetManager :AFHTTPSessionManager {
/// 初始化RequsetManager單利
static let sharedRequestManager:RequsetManager = {
let instance = RequsetManager()
instance.requestSerializer.timeoutInterval = 60.0
//自定義設置請求頭
// instance.requestSerializer.setValue(<#T##value: String?##String?#>, forHTTPHeaderField: <#T##String#>)
instance.responseSerializer = AFHTTPResponseSerializer()
return instance
}()
/// GET請求
///
/// - Parameters:
/// - url: 請求地址
/// - params: 請求參數(shù)
/// - success: 請求成功回調
/// - failure: 請求失敗回調
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請求
///
/// - Parameters:
/// - url: 請求地址
/// - params: 請求參數(shù)
/// - success: 請求成功回調
/// - failure: 請求失敗回調
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.對比--使用--分析
Swift版本其實就是對OC版本的一個更改在RequsetManager層次幾乎是一樣的,在Service層,OC版本需要在使用的時候將所要轉換的對象的Class當做參數(shù)傳過來,而在Swift版本中,僅僅需要在閉包中用泛型就可以,無需再需要傳遞對象的類
在使用上,OC版本回調回去的是一個id對象,無論是對象數(shù)組抑或是對象,都需要強制轉換后使用,而在Swift版本中,我用了多態(tài)的性質,根據(jù)使用時傳遞的閉包不同,返回的結果也不同,結果是對象的和結果是對象數(shù)組的,可以分別選擇調用相對應的方法.
使用
返回結果是對象的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進行強轉...
NSLog(@"結果為對象---%@",((TestModel *)dataObj).message);
}];
}
返回結果是對象數(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 ;
}
//此時沒必要強制轉換,如果網(wǎng)絡數(shù)據(jù)返回的是數(shù)組,得到的dataObj肯定是數(shù)組
而且里面的對象肯定是傳的modelClass對象
for (TestModel * mode in dataObj) {
NSLog(@"結果為對象數(shù)組--%@",mode.message);
}
}];
返回結果是對象的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
}
//調用方法的時候TestModel是當做泛型傳遞過去的,所以回調的model
是可以直接來使用的
print("結果為對象--->\(model?.message ?? "NoMessage")")
}
返回結果是對象數(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
}
//運用傳遞的閉包不同,返回的modelArr的泛型為TestModel
所以返回過來之后可以直接使用了
if let arr = modelArr{
for item in arr{
print("結果為對象數(shù)組--->\(item.message ?? "NoMessage")")
}
}
}
分析,這兩中其實思想是一樣的,只不過Swift版本因為使用了泛型,所以在使用的時候更加清晰,而且也不需要將所要轉換的對象類當做參數(shù)進行傳遞,而且使用了多態(tài),根據(jù)返回的結果不同分別傳遞不同的閉包,而OC版本,始終都是那一個方法,需要對返回的結果進行強制轉換,所以使用起來沒有那么的一目了然,大致就是這樣,希望我這個可以拋磚引玉,有好的想法的童鞋可以給我留言交流,共同提高
8.寫在最后
最后提醒一下,我請求的地址是我使用Java寫的本地的一個服務,小伙伴們在使用的時候可要進行相對應的更改哦,最后奉上我測試的結果截圖,有什么不足呢,可以給我留言溝通共同提高哦.謝謝
10.最后的最后,奉上完整的Demo地址(XML轉JSON的類在OC源碼中)