网络接口请求
基本上目前市面上所有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];
}];
}];
共同学习进步!