網絡接口請求
基本上目前市面上所有app都需要有的功能模塊,通過網絡接口從服務器獲取業務數據。
網絡請求模塊盡可能與UI界面邏輯分開,在Controller請求數據時盡可能簡單。此文將對接口請求模塊作一簡單地封裝。
簡要分析
1、API接口請求需要統一入口統一管理。
2、具體的http任務請求(即單個的請求任務HttpClient,不帶業務相關邏輯)。
3、跟業務相關的接口定義如接口標識,接口地址。
4、接口請求數據需要簽名或者加密。
5、服務器響應后的數據需要按業務解析成UI能用的數據結構對象。
6、接口請求完成后回調。
對象模型
- PGRequestManager 接口請求管理,為所有業務數據請求提供統一的入口
- PGHttpClient 封裝具體的網絡http請求邏輯
- PGAPI 封裝業務相關的接口地址與解析數據入口
- PGEncrypt 封裝一些加密操作,如接口簽名等
- PGDataParseManager 接口請求的回來的數據進行解析
- PGResultObject 接口請求解析完成后返回給View的數據
PGAPI
定義相關的業務數據接口標識Type,如登錄、注冊等。
typedef NS_ENUM(NSUInteger, PGApiType) {
API_TYPE_LOGIN = 1,//登錄
API_TYPE_REGIEST,//注冊
API_TYPE_PRODUCT_LIST,//產品列表
};
定義Api委托協議
@protocol PGApiDelegate <NSObject>
@required
- (void)dataRequestSuccess:(PGResultObject *)resultObj;
- (void)dataRequestFailed:(PGResultObject *)resultObj;
@end
添加獲取接口地址與接口數據解析的統一入口。
@interface PGAPI : NSObject
/*
獲取相應的接口地址
*/
+ (NSString *)urlStringWithType:(PGApiType)type;
/*
解析數據入口
*/
+ (id)parseDataWithType:(PGApiType)type data:(id)data;
@end
//PGAPI.m
@implementation PGAPI
+ (NSString *)urlStringWithType:(PGApiType)type
{
NSString *urlString = nil;
switch(type)
{
case API_TYPE_LOGIN: {
urlString = [NSString stringWithFormat:@"%@%@",BASE_URL,@"/u/user/login"];
break;
}
case API_TYPE_REGIEST: {
urlString = [NSString stringWithFormat:@"%@%@",BASE_URL,@"/u/user/regiest"];
break;
}
default:
break;
}
return urlString;
}
+ (id)parseDataWithType:(PGApiType)type data:(id)data
{
NSObject *result = nil;
switch(type)
{
case API_TYPE_LOGIN: {
result = [PGDataParseManager parseLogin:data];
break;
}
case API_TYPE_REGIEST: {
break;
}
default:
break;
}
return result;
}
@end
PGHttpClient 封裝具體的網絡http請求邏輯
@class PGHttpClient;
@protocol PGHttpClientDelegate <NSObject>
@required
- (void)dataRequestSuccess:(PGResultObject *)resultObj client:(PGHttpClient *)client;
- (void)dataRequestFailed:(PGResultObject *)resultObj client:(PGHttpClient *)client;
@end
/*
根據業務封裝Api接口數據
*/
@interface PGHttpClient : NSObject
@property(nonatomic, assign, readonly)PGApiType apiType;
@property(nonatomic, weak)id<PGApiDelegate> apiDelegate;
@property(nonatomic, weak)id<PGHttpClientDelegate> delegate;
@property(nonatomic, copy)NSString *requestMethod;
/*
請求策略所用的key值,緩存接口數據與讀取接口數據時用。
*/
@property(nonatomic, copy)NSString *strategyKey;
/**
type: API接口類型
dicParam: 請求參數
*/
- (instancetype)initWithType:(PGApiType)type requestParam:(NSDictionary *)dicParam;
/**
開始請求數據
*/
- (void)startRequest;
/**
取消數據請求
*/
- (void)cancelRequest;
/**
解析接口返回的json字符數據
*/
- (void)parseData:(NSString *)szString;
@end
PGEncrypt 封裝一些加密操作,如接口簽名等
@interface PGEncrypt : NSObject
/*
創建接口簽名
*/
+ (NSString *)createSignWith:(NSDictionary *)dictionary;
@end
PGResultObject
#import <Foundation/Foundation.h>
@interface PGResultObject : NSObject
/*
錯誤編號
*/
@property(nonatomic, assign)NSInteger nCode;
/*
錯誤描述
*/
@property(nonatomic, strong)NSString *szErrorDes;
/*
接口返回的數據
*/
@property(nonatomic, strong)id dataObject;
@end
PGDataParseManager 所有的業務數據解析,統一一個地方方便修改。
/**
數據解析管理器,api所有的接口數據都在此文件中解析,方便維護
*/
@interface PGDataParseManager : NSObject
/**
登錄數據解析
*/
+ (id)parseLogin:(NSDictionary *)dictionary;
@end
PGRequestManager 接口請求管理,為所有業務數據請求提供統一的入口
@interface PGRequestManager : NSObject
//普通接口請求
+ (void)startPostClient:(PGApiType)type param:(NSDictionary *)param target:(id<PGApiDelegate>)target tag:(NSString *)tag;
+ (void)startGetClient:(PGApiType)type param:(NSDictionary *)param target:(id<PGApiDelegate>)target tag:(NSString *)tag;
//取消請求
+ (void)cancelClientWithTarget:(id)target tag:(NSString *)tag;
@end
調用示例
[self showWaitingView:nil viewStyle:EWaitingViewStyle_Rotation];
[PGRequestManager startPostClient:API_TYPE_LOGIN
param:@{@"userName":@"name",@"password":@"123456"}
target:self
tag:@"login"];
回調處理
- (void)dataRequestSuccess:(PGResultObject *)resultObj
{
[self hideWaitingView];
}
- (void)dataRequestFailed:(PGResultObject *)resultObj
{
[self hideWaitingView];
[self showMsg:resultObj.szErrorDes];
}
當然也可以設計用Block回調,我這采用delegate主要是考慮到Controller的延遲銷毀問題。也就是說Controller已經推出,但接口請求還沒停止。block設計方案:
WEAKSELF
[PGRequestManager startPostClient:EUCClientType_Login param:@{@"userName":@"name",@"password":@"123456"} target:self tag:@"login" success:^(PGResultObject *resultObj) {
[weakSelf asyncOnMainQueue:^{
}];
} faile:^(UCResultObject *resultObj) {
[weakSelf asyncOnMainQueue:^{
[weakSelf showMsg:resultObj.szErrorDes];
}];
}];
共同學習進步!