iOS 網(wǎng)絡(luò)層架構(gòu)

前言

在此所說(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)題

  1. 網(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)了。
  2. 網(wǎng)絡(luò)請(qǐng)求處理過(guò)程重復(fù)啰嗦,而又驚人的相似。那么在網(wǎng)絡(luò)請(qǐng)求過(guò)程處理上的復(fù)用就顯得非常有必要。
  3. 取消網(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ù)層面的選擇與看法

  1. 跟業(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í)都能夠避免。

  1. 集約型和離散型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)思想

  1. 配置對(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)用的一種變相。
  2. 多層控制架構(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ì)思想
  1. 自動(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)該取消。
  2. 設(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)便之處。
  3. 實(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ò)程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容