前言
在此所說(shuō)的網(wǎng)絡(luò)層架構(gòu),無(wú)非就是針對(duì)iOS網(wǎng)絡(luò)請(qǐng)求的現(xiàn)狀與問(wèn)題,做出相應(yīng)的解決方案。
iOS網(wǎng)絡(luò)請(qǐng)求的現(xiàn)狀與問(wèn)題
- 網(wǎng)絡(luò)接口規(guī)范化:所謂的規(guī)范、沒(méi)有什么一定的規(guī)范,每個(gè)人都有每個(gè)人的規(guī)范,無(wú)破不立,也總會(huì)有不在規(guī)范之類的。雖然網(wǎng)絡(luò)接口規(guī)范化能帶來(lái)很多好處,可是開(kāi)發(fā)中往往會(huì)遇到特例。很多時(shí)候,我們無(wú)法要求別人要怎樣配合自己。那么唯有靈活多變,而又方便易用的網(wǎng)絡(luò)框架被提到日程上來(lái)了。
- 網(wǎng)絡(luò)請(qǐng)求處理過(guò)程重復(fù)啰嗦,而又驚人的相似。那么在網(wǎng)絡(luò)請(qǐng)求過(guò)程處理上的復(fù)用就顯得非常有必要。
- 取消網(wǎng)絡(luò)請(qǐng)求麻煩,不能自動(dòng)取消不必要的請(qǐng)求。那么也就需要對(duì)網(wǎng)絡(luò)請(qǐng)求的取消做一些分裝,提高一些所謂的性能。
這個(gè)版本的主要針對(duì)以上三個(gè)方面進(jìn)行的架構(gòu),以后升級(jí)會(huì)往網(wǎng)絡(luò)安全與性能優(yōu)化方向靠。
技術(shù)層面的選擇與看法
- 跟業(yè)務(wù)層對(duì)接的交互模式
跟業(yè)務(wù)層對(duì)接主要就Delegate,Notification,Block,KVO和Target-Action這幾種方式吧;它們之間有好壞優(yōu)劣我不想在此比較,可以自行查閱。我選擇的方式是Block,沒(méi)有其他原因,有且只有一個(gè)那就是Block簡(jiǎn)單粗暴,用起來(lái)方便、用起來(lái)爽在我看來(lái)很重要,所謂的那些問(wèn)題其實(shí)都能夠避免。
- 集約型和離散型API調(diào)用方式
先來(lái)解釋一下離散型吧,“離散型API調(diào)用是這樣的,一個(gè)API對(duì)應(yīng)于一個(gè)APIManager”,聽(tīng)到這句話我就煩,我就pass掉了,一個(gè)API對(duì)應(yīng)于一個(gè)APIManager。其實(shí)每個(gè)請(qǐng)求之間是多么驚人的相似,而用一個(gè)獨(dú)立的Manager來(lái)管理,我有點(diǎn)無(wú)法接受?;蛟S在自動(dòng)取消這樣的問(wèn)題上有點(diǎn)優(yōu)勢(shì)吧。
網(wǎng)絡(luò)層架構(gòu)實(shí)現(xiàn)
AFNetworking基本是iOS網(wǎng)絡(luò)請(qǐng)求的標(biāo)配,各種優(yōu)勢(shì)不用言表,這個(gè)框架也是基于AFN針對(duì)上述問(wèn)題與目標(biāo)進(jìn)行的二次封裝架構(gòu)。
架構(gòu)思想
- 配置對(duì)象架構(gòu):由于本著靈活多變目標(biāo),我在幾度考量之后決定使用配置對(duì)象的方式進(jìn)行架構(gòu),如果對(duì)配置對(duì)象進(jìn)行多層控制,相互組合能夠非常靈活控制網(wǎng)絡(luò)請(qǐng)求。再一個(gè)就是使用配置對(duì)象能夠承載非常多的參數(shù)、而通常情況這些參數(shù)有基本相同,通過(guò)默認(rèn)參數(shù)就可以解決掉相當(dāng)一部分問(wèn)題,遇到特殊情況再特殊配置,這樣相當(dāng)?shù)暮?jiǎn)潔而又易于擴(kuò)展。其實(shí)從這個(gè)方面來(lái)看,這種使用配置對(duì)象的方式起到了離散型API調(diào)用的作用,說(shuō)白了也算是離散型API調(diào)用的一種變相。
- 多層控制架構(gòu):多層控制考慮更多的是對(duì)網(wǎng)絡(luò)請(qǐng)求過(guò)程的復(fù)用,另一個(gè)就是這樣多層組合靈活性更大,業(yè)務(wù)層有更大的發(fā)揮空間。
配置對(duì)象的實(shí)現(xiàn)
本次網(wǎng)絡(luò)層架構(gòu)主要依賴于QSPNetworkingConfig(網(wǎng)絡(luò)控制)、QSPParameterConfig(請(qǐng)求空)、QSPLoadConfig(加載處理)、QSPErrorConfig(錯(cuò)誤處理)這四個(gè)配置對(duì)象,下面分別介紹。
QSPNetworkingConfig配置對(duì)象的實(shí)現(xiàn)
QSPNetworkingConfig:這個(gè)配置對(duì)象用于配置網(wǎng)絡(luò)層的參數(shù),說(shuō)白了就是表示一個(gè)AFHTTPSessionManager對(duì)象。目前抽象出如下參數(shù)進(jìn)行控制,如后期有需要完全可以自由添加,擴(kuò)展性非常高
/**
超時(shí)時(shí)間(默認(rèn):15)
*/
@property (assign, nonatomic) NSTimeInterval timeoutInterval;
/**
服務(wù)器地址
*/
@property (copy, nonatomic) NSString *basePath;
/**
驗(yàn)證模式(默認(rèn):AFSSLPinningModeNone)
*/
@property (nonatomic, assign) AFSSLPinningMode SSLPinningMode;
/**
本地綁定的證書(shū)(默認(rèn):nil)
*/
@property (nonatomic, strong) NSSet <NSData *> *pinnedCertificates;
/**
是否允許無(wú)效證書(shū)(默認(rèn):NO)
*/
@property (nonatomic, assign) BOOL allowInvalidCertificates;
/**
是否驗(yàn)證域名(默認(rèn):NO)
*/
@property (nonatomic, assign) BOOL validatesDomainName;
/**
數(shù)據(jù)解析格式(默認(rèn):[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", @"text/plain", nil])
*/
@property (copy, nonatomic) NSSet<NSString *> *acceptableContentTypes;
/**
請(qǐng)求頭設(shè)置字典(默認(rèn):[NSDictionary dictionaryWithObject:@"ios" forKey:@"request-type"])
*/
@property (copy, nonatomic) NSDictionary<NSString *, NSString *> *HTTPHeaderDictionary;
QSPLoadConfig配置對(duì)象的實(shí)現(xiàn)
QSPLoadConfig:這個(gè)配置對(duì)象就是對(duì)網(wǎng)絡(luò)請(qǐng)求過(guò)程進(jìn)行控制,目前只有對(duì)只使用loadBegin、loadEnd兩個(gè)block對(duì)開(kāi)始請(qǐng)求和結(jié)束請(qǐng)求兩個(gè)節(jié)點(diǎn)進(jìn)行控制,非常簡(jiǎn)單在此略去。
QSPErrorConfig配置對(duì)象的實(shí)現(xiàn)
QSPErrorConfig:這個(gè)配置對(duì)象控制著網(wǎng)絡(luò)請(qǐng)求的錯(cuò)誤處理,這里把錯(cuò)誤區(qū)分為網(wǎng)絡(luò)請(qǐng)求錯(cuò)誤與返回的數(shù)據(jù)錯(cuò)誤兩種形式如下:
/**
網(wǎng)絡(luò)錯(cuò)誤處理(默認(rèn)無(wú))
*/
@property (copy, nonatomic) QSPNetworkingErrorBlock networkingErrorPrompt;
/**
數(shù)據(jù)錯(cuò)誤處理(默認(rèn)無(wú))
*/
@property (copy, nonatomic) QSPDataErrorBlock dataErrorPrompt;
QSPParameterConfig配置對(duì)象的實(shí)現(xiàn)
QSPParameterConfig:這個(gè)配置對(duì)象是對(duì)網(wǎng)絡(luò)請(qǐng)求參數(shù)控制,不僅包含了網(wǎng)絡(luò)請(qǐng)求所需要的各種參數(shù),還包涵了上三個(gè)配置對(duì)象、這樣可以為每條請(qǐng)求做出特定的控制,達(dá)到離散型API調(diào)用的效果。它的屬性與工廠方法如下:
/**
請(qǐng)求參數(shù)
*/
@property (copy, nonatomic) NSDictionary *parameters;
/**
請(qǐng)求類型(默認(rèn)為POST)
*/
@property (assign, nonatomic) QSPNetworkingType type;
/**
上傳文件數(shù)組(默認(rèn)為nil)
*/
@property (copy, nonatomic) NSArray<QSPUploadModel *> *uploadModels;
/**
請(qǐng)求api
*/
@property (copy, nonatomic) NSString *apiPath;
/**
是否自動(dòng)取消(默認(rèn)為YES)
*/
@property (assign, nonatomic) BOOL autoCancel;
/**
自動(dòng)取消操作的依賴對(duì)象(此對(duì)象一銷毀,就執(zhí)行取消操作,所以autoCancel設(shè)置為YES的時(shí)候必須設(shè)置此參數(shù)自動(dòng)取消才會(huì)起作用,默認(rèn)為nil)
*/
@property (weak, nonatomic) id cancelDependence;
/**
網(wǎng)絡(luò)請(qǐng)求發(fā)生的控制器(默認(rèn)為nil)
*/
@property (weak, nonatomic) UIViewController *controller;
/**
是否處理錯(cuò)誤(默認(rèn)為YES)
*/
@property (assign, nonatomic) BOOL showError;
/**
是否顯示加載(默認(rèn)為YES)
*/
@property (assign, nonatomic) BOOL showLoad;
/**
是否執(zhí)行成功的條件(默認(rèn)為YES,如果為NO,只要網(wǎng)絡(luò)請(qǐng)求成功就表示成功)
*/
@property (assign, nonatomic) BOOL executeConditionOfSuccess;
/**
網(wǎng)絡(luò)配置對(duì)象(默認(rèn)為nil)
*/
@property (strong, nonatomic) QSPNetworkingConfig *networkingConfig;
/**
錯(cuò)誤配置對(duì)象(默認(rèn)為nil)
*/
@property (strong, nonatomic) QSPErrorConfig *errorConfig;
/**
加載配置對(duì)象(默認(rèn)為nil)
*/
@property (strong, nonatomic) QSPLoadConfig *lodaConfig;
/**
進(jìn)度回調(diào)(默認(rèn)為nil)
*/
@property (copy, nonatomic) QSPProgressBolck progress;
/**
請(qǐng)求完成回調(diào)(默認(rèn)為nil)
*/
@property (copy, nonatomic) QSPCompletionBlock completion;
+ (instancetype)parameterConfigWithParameters:(NSDictionary *)parameters apiPath:(NSString *)apiPath cancelDependence:(id)cancelDependence controller:(UIViewController *)controller completion:(QSPCompletionBlock)completion;
- (instancetype)initWithParameters:(NSDictionary *)parameters apiPath:(NSString *)apiPath cancelDependence:(id)cancelDependence controller:(UIViewController *)controller completion:(QSPCompletionBlock)completion;
核心邏輯實(shí)現(xiàn)
QSPNetworkingManager
QSPNetworkingManager:這是網(wǎng)絡(luò)管理對(duì)象,使用QSPNetworkingConfig、QSPErrorConfig、QSPLoadConfig三個(gè)配置對(duì)象配置并控制著。然而每個(gè)請(qǐng)求的發(fā)送都會(huì)提供一個(gè)QSPNetworkingConfig配置對(duì)象這個(gè)對(duì)象有著更高的控制能力,這樣就達(dá)到了兩層控制,QSPNetworkingConfig其實(shí)為方便起見(jiàn)又用參數(shù)對(duì)某些地方進(jìn)行控制,可以說(shuō)有的具有三層控制。其頭文件如下:
/**
配置對(duì)象
*/
@property (strong, nonatomic) QSPNetworkingConfig *config;
/**
錯(cuò)誤配置對(duì)象
*/
@property (strong, nonatomic) QSPErrorConfig *errorConfig;
/**
加載配置對(duì)象
*/
@property (strong, nonatomic) QSPLoadConfig *loadConfig;
/**
成功的條件(如果不設(shè)置,只要網(wǎng)絡(luò)請(qǐng)求成功,就認(rèn)為是成功)
*/
@property (copy, nonatomic) QSPConditionOfSuccessBolck conditionOfSuccess;
/**
配置框架
@param networkingConfig 網(wǎng)絡(luò)配置
@param errorConfig 錯(cuò)誤配置
@param loadConfig 加載配置
@param condictionOfSuccess 成功的條件(如果不設(shè)置,只要網(wǎng)絡(luò)請(qǐng)求成功,就認(rèn)為是成功)
*/
+ (void)configWithNetworkingConfig:(QSPNetworkingConfig *)networkingConfig errorConfig:(QSPErrorConfig *)errorConfig loadConfig:(QSPLoadConfig *)loadConfig condictionOfSuccess:(QSPConditionOfSuccessBolck)condictionOfSuccess;
/**
單例方法
*/
+ (instancetype)manager;
/**
默認(rèn)調(diào)用(POST方式調(diào)用,最終轉(zhuǎn)化為callWithParameterConfig方法調(diào)用)
@param apiPath api
@param parameters 參數(shù)
@param dependence 依賴對(duì)象
@param completion 完成的回調(diào)
@return QSPNetworkingObject對(duì)象
*/
+ (QSPNetworkingObject *)defaultCall:(NSString *)apiPath parameters:(NSDictionary *)parameters cancelDependence:(id)dependence controller:(UIViewController *)controller completion:(QSPCompletionBlock)completion;
/**
get調(diào)用(最終轉(zhuǎn)化為callWithParameterConfig方法調(diào)用)
@param apiPath api
@param parameters 參數(shù)
@param dependence 依賴對(duì)象
@param completion 完成的回調(diào)
@return QSPNetworkingObject對(duì)象
*/
+ (QSPNetworkingObject *)getCall:(NSString *)apiPath parameters:(NSDictionary *)parameters cancelDependence:(id)dependence controller:(UIViewController *)controller completion:(QSPCompletionBlock)completion;
/**
使用配置對(duì)象調(diào)用
@param parameterConfig 配置對(duì)象
@return QSPNetworkingObject對(duì)象
*/
+ (QSPNetworkingObject *)callWithParameterConfig:(QSPParameterConfig *)parameterConfig;
QSPNetworkingConfig對(duì)應(yīng)AFHTTPSessionManager的設(shè)置
- (AFHTTPSessionManager *)sessionManagerWithNetworkingConfig:(QSPNetworkingConfig *)config
{
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:config.basePath]];
sessionManager.requestSerializer.timeoutInterval = config.timeoutInterval;
sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
sessionManager.responseSerializer = serializer;
[config.HTTPHeaderDictionary enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
[sessionManager.requestSerializer setValue:key forHTTPHeaderField:obj];
}];
sessionManager.responseSerializer.acceptableContentTypes = config.acceptableContentTypes;
sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:config.SSLPinningMode];
sessionManager.securityPolicy.allowInvalidCertificates = config.allowInvalidCertificates;//忽略https證書(shū)
sessionManager.securityPolicy.validatesDomainName = config.validatesDomainName;//是否驗(yàn)證域名
return sessionManager;
}
請(qǐng)求執(zhí)行過(guò)程(以POST方式為例)
[sessionManager POST:parameterConfig.apiPath parameters:parameterConfig.parameters constructingBodyWithBlock:^(id <AFMultipartFormData> formData) {
//上傳文件
for (QSPUploadModel *uploadModel in parameterConfig.uploadModels) {
[formData appendPartWithFileData:uploadModel.data name:uploadModel.name fileName:uploadModel.fileName mimeType:uploadModel.mimeType];
}
} progress:^(NSProgress * _Nonnull uploadProgress) {
//出來(lái)進(jìn)度
if (parameterConfig.progress) {
parameterConfig.progress(uploadProgress);
}
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//成功著陸
[weakSelf susseccWithParameterConfig:parameterConfig task:task responseObject:responseObject];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
//失敗著陸
[weakSelf failureWithParameterConfig:parameterConfig task:task error:error];
}];
請(qǐng)求成功著陸的執(zhí)行過(guò)程
- (void)susseccWithParameterConfig:(QSPParameterConfig *)parameterConfig task:(NSURLSessionDataTask *)task responseObject:(id)responseObject
{
//打印請(qǐng)求信息
QSPNetworkingLog(@"\n接口地址:%@\n接口參數(shù):%@\n上傳文件:%@\n接口返回:%@", task.currentRequest.URL.absoluteString, parameterConfig.parameters, parameterConfig.uploadModels, responseObject);
[self removeDependence:parameterConfig andTask:task];
[self removeLoad:parameterConfig];
//出來(lái)數(shù)據(jù)錯(cuò)誤
if (parameterConfig.showError) {
//選擇QSPErrorConfig,這里以parameterConfig的優(yōu)先級(jí)高
QSPErrorConfig *errorConfig = parameterConfig.errorConfig ? parameterConfig.errorConfig : self.errorConfig;
if (errorConfig.dataErrorPrompt) {
errorConfig.dataErrorPrompt(responseObject, parameterConfig.controller);
}
}
//執(zhí)行成功條件
if (parameterConfig.executeConditionOfSuccess) {
if (self.conditionOfSuccess) {
if (self.conditionOfSuccess(responseObject)) {
if (parameterConfig.completion) {
parameterConfig.completion(YES, responseObject, nil);
}
}
else
{
if (parameterConfig.completion) {
parameterConfig.completion(NO, responseObject, nil);
}
}
}
else
{
if (parameterConfig.completion) {
parameterConfig.completion(YES, responseObject, nil);
}
}
}
else
{
if (parameterConfig.completion) {
parameterConfig.completion(YES, responseObject, nil);
}
}
}
對(duì)單例的設(shè)計(jì)方式進(jìn)行說(shuō)明
QSPNetworkingManager這個(gè)管理對(duì)象采用的是單例的設(shè)計(jì)模式,設(shè)計(jì)之初是為了避免麻煩的創(chuàng)建過(guò)程,但是隨著框架在項(xiàng)目中的使用,我發(fā)現(xiàn)單例的設(shè)計(jì)模式限制了一定的靈活性,以后我一定會(huì)對(duì)此作出調(diào)整。為什么如此說(shuō),是因?yàn)殡m然兩層控制已經(jīng)很靈活了,普遍適應(yīng)了基本請(qǐng)求、特例請(qǐng)求這種模式。然而計(jì)劃永遠(yuǎn)趕不上變化,如果基本請(qǐng)求形式有很多種呢?
自動(dòng)取消的設(shè)計(jì)
設(shè)計(jì)思想
- 自動(dòng)取消時(shí)機(jī):自動(dòng)取消,如何取消,什么情況取消?其實(shí)普遍來(lái)說(shuō)當(dāng)一個(gè)視圖控制器銷毀的時(shí)候,起生命周期內(nèi)發(fā)送的任何網(wǎng)絡(luò)請(qǐng)求只要沒(méi)有著陸的都應(yīng)該取消。
- 設(shè)計(jì)方案:為每一條請(qǐng)求設(shè)置一個(gè)自動(dòng)取消操作的依賴對(duì)象,只要依賴對(duì)象銷毀,那么我們就取消請(qǐng)求。有人說(shuō)使用離散型API調(diào)用來(lái)實(shí)現(xiàn)要好,不需要設(shè)置依賴對(duì)象,我想說(shuō)的是其實(shí)一樣,離散型方式視圖控制器就需要持有APIManager,并沒(méi)有任何不簡(jiǎn)便之處。
- 實(shí)現(xiàn)步驟
- 包裝一個(gè)能夠取消網(wǎng)絡(luò)請(qǐng)求的QSPNetworkingObject對(duì)象,其頭文件如下:
/**
網(wǎng)絡(luò)請(qǐng)求對(duì)象
*/
@interface QSPNetworkingObject : NSObject
@property (strong, nonatomic, readonly) NSURLSessionTask *task;
+ (instancetype)networkingObjectWithTask:(NSURLSessionTask *)task autoCancel:(BOOL)autoCancel;
- (instancetype)initWithTask:(NSURLSessionTask *)task autoCancel:(BOOL)autoCancel;
/**
取消請(qǐng)求
*/
- (void)cancel;
@end
- 動(dòng)態(tài)給取消依賴對(duì)象添加能夠取消請(qǐng)求的網(wǎng)絡(luò)對(duì)象(如上步驟所述),這里使用的數(shù)組,然后再把網(wǎng)絡(luò)對(duì)象加在數(shù)組中,因?yàn)榇嬖诙鄠€(gè)請(qǐng)求依賴一個(gè)對(duì)象,具體如下:
QSPNetworkingObject *obj = [QSPNetworkingObject networkingObjectWithTask:task autoCancel:(parameterConfig.autoCancel && parameterConfig.cancelDependence) ? YES : NO];
if (parameterConfig.autoCancel && parameterConfig.cancelDependence) {
NSMutableArray *networkingObjects = objc_getAssociatedObject(parameterConfig.cancelDependence, QSPNetworkingObject_arrayName);
if (networkingObjects == nil) {
networkingObjects = [NSMutableArray arrayWithCapacity:1];
objc_setAssociatedObject(parameterConfig.cancelDependence, QSPNetworkingObject_arrayName, networkingObjects, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
if (obj) {
[networkingObjects addObject:obj];
}
}
- 取消網(wǎng)絡(luò)請(qǐng)求,因?yàn)橐蕾噷?duì)象銷毀的時(shí)候,上步驟中添加包裝取消網(wǎng)絡(luò)請(qǐng)求的對(duì)象也隨之銷毀,所以在其dealloc方法中把網(wǎng)絡(luò)請(qǐng)求取消掉。
- (void)dealloc
{
// QSPNetworkingLog(@"%@取消啦---------------------------------------------------", self.task.currentRequest.URL.absoluteString);
if (self.autoCancel) {
[self cancel];
}
}
- (void)cancel
{
// QSPNetworkingLog(@"---------------------------------------------------%@%zi", self.task.currentRequest.URL.absoluteString, self.task.state);
if (self.task.state != NSURLSessionTaskStateCompleted && self.task.state != NSURLSessionTaskStateCanceling) {
QSPNetworkingLog(@"---------------------------------------------------%@取消啦", self.task.currentRequest.URL.absoluteString);
[self.task cancel];
}
}
- 把動(dòng)態(tài)給依賴對(duì)象中添加對(duì)象移除掉,在每一條請(qǐng)求著陸后都移除,避免依賴對(duì)象持有太多的之前包裝的具有取消網(wǎng)絡(luò)請(qǐng)求能力的對(duì)象。
NSMutableArray *networkingObjects = objc_getAssociatedObject(parameterConfig.cancelDependence, QSPNetworkingObject_arrayName);
if (networkingObjects) {
QSPNetworkingObject *netObj;
for (QSPNetworkingObject *obj in networkingObjects) {
if (obj.task == task) {
netObj = obj;
break;
}
}
[networkingObjects removeObject:netObj];
}
框架的使用
配置網(wǎng)絡(luò)框架
此網(wǎng)絡(luò)框架的配置需要QSPNetworkingConfig(網(wǎng)絡(luò)配置對(duì)象)、QSPErrorConfig(錯(cuò)誤處理配置對(duì)象)、QSPLoadConfig(加載處理配置對(duì)象)以及一個(gè)判斷網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)正確的block共同完成。
- (void)configNetworking {
//創(chuàng)建網(wǎng)絡(luò)配置對(duì)象,控制網(wǎng)絡(luò)請(qǐng)求
QSPNetworkingConfig *networkingConfig = [QSPNetworkingConfig networkingConfigWithBasePath:K_NetService_Base];
//創(chuàng)建錯(cuò)誤處理配置對(duì)象,處理網(wǎng)絡(luò)、數(shù)據(jù)錯(cuò)誤
QSPErrorConfig *errorConfig = [QSPErrorConfig errorConfigWithNetworkingErrorPrompt:^(NSError *error, UIViewController *controller) {
if (error.code == -999) {
[LoadClass showMessage:K_NetRequestMessage_Cancel toView:self.window];
}
else if (error.code == -1001)
{
[LoadClass showMessage:K_NetRequestMessage_TimeOut toView:controller.view];
}
else
{
[LoadClass showMessage:K_NetRequestMessage_Failure toView:controller.view];
}
} dataErrorPrompt:^void(id responseObject, UIViewController *controller) {
if (responseObject == nil || [responseObject isKindOfClass:[NSNull class]]) {
[LoadClass showMessage:K_NetRequestMessage_NoData toView:controller.view];
} else {
if ([responseObject[@"status"] intValue] != 1) {
NSString *message = responseObject[@"message"] ? responseObject[@"message"] : K_NetRequestMessage_Error;
[LoadClass showMessage:message toView:controller.view];
}
}
}];
//創(chuàng)建加載處理配置對(duì)象,處理加載過(guò)程
QSPLoadConfig *loadConfig = [QSPLoadConfig loadConfigWithLoadBegin:^(UIViewController *controller){
[LoadClass beginLoadWithMessage:K_NetRequestMessage_Load toView:controller.view];
} loadEnd:^(UIViewController *controller){
[LoadClass endLoadFromView:controller.view];
}];
//配置網(wǎng)絡(luò)框架
[QSPNetworkingManager configWithNetworkingConfig:networkingConfig errorConfig:errorConfig loadConfig:loadConfig condictionOfSuccess:^BOOL(id responseObject) {
return [responseObject[@"status"] integerValue] == 1;
}];
}
發(fā)送請(qǐng)求
分裝了如下三個(gè)方法來(lái)發(fā)送請(qǐng)求,分別為默認(rèn)方式(post)、get方式、參數(shù)配置方式(可以通過(guò)配置對(duì)象配置各種適合自己的請(qǐng)求)。
+ (QSPNetworkingObject *)defaultCall:(NSString *)apiPath parameters:(NSDictionary *)parameters cancelDependence:(id)dependence controller:(UIViewController *)controller completion:(QSPCompletionBlock)completion;
+ (QSPNetworkingObject *)getCall:(NSString *)apiPath parameters:(NSDictionary *)parameters cancelDependence:(id)dependence controller:(UIViewController *)controller completion:(QSPCompletionBlock)completion;
+ (QSPNetworkingObject *)callWithParameterConfig:(QSPParameterConfig *)parameterConfig;
發(fā)送一個(gè)get請(qǐng)求
[QSPNetworkingManager getCall:K_NetService_Regeo parameters:K_NetService_RegeoParamery cancelDependence:weakSelf controller:weakSelf completion:^(BOOL success, id responseObject, NSError *error) {
if (success) {
[LoadClass showMessage:@"請(qǐng)求成功!" toView:weakSelf.view];
}
}];
[weakSelf.navigationController popViewControllerAnimated:NO];
最后當(dāng)然是代碼地址
預(yù)告
下一篇記錄下把這個(gè)框架加入到CocoaPods中管理的全過(guò)程。