iOS网络层设计-Engine 实现

作者: 3697d6c42285 | 来源:发表于2017-05-13 14:08 被阅读158次

    iOS 网络层设计


    iOS 网络层 Engine 的功能

    • 调用 Client 实现请求
    • 配置请求信息
    • 回调结果解析并返回到上层
    • 取消请求

    Engine 是使用层调用的,连接着 Client 和使用者。使用者通过 Engine 进行初步处理之后调用 Client。

    iOS 网络层 Engine 的分类

    Engine 会通过不同的分类,还会额外实现一些特殊的功能:每次都只会请求一次、不允许取消的、多次请求的等。以此,我将 Engine 暂时分类以下几类:

    • 数据上传的 Engine;(UploadEngine)
    • 获取服务器固定数据的 Engine;(DownLoadEngine)
    • 需要多次请求的 Engine;(MutipleEngine)

    数据上传的 Engine:由于取消请求并不能把你的请求从网络中取消掉,只能取消掉着陆点,所以上传的时候,不允许取消请求。而获取服务器固定数据的话,通过实例化的对象,以最后一次的调用为准,之前的请求全部取消。
    获取服务器固定数据的 Engine:如果需要获取服务器的数据,一般都是以最后一次操作为准,如刷新或者加载更多,如果一次性多个请求,在 tableView 刷新数据的时候,有可能会发生刷新过程中,数据源被代替导致崩溃。
    需要多次请求的 Engine:在例如多张图片上传的时候,需要判断哪个请求成功,哪个请求失败。在全部请求结束之后做什么操作。

    iOS 网络层 Engine 的功能实现

    首先是 BaseAPIConfig 的实现:

    
    @interface BaseAPIConfig : NSObject
    /// 地址
    @property (nonatomic, copy) NSString *url;
    /// 方法
    @property (nonatomic, copy) NSString *method;
    /// 参数
    @property (nonatomic, copy) NSDictionary *param;
    
    @end
    
    

    BaseAPIConfig 是方法接口配置的参数,后面回根据需求或者分类不同而增加或减少。将参数提取出来单独归类是为了让方法的参数减少,并且在以后增加参数的时候,不需要增加方法,只需修改原先方法即可。
    url 是请求地址,是所有的请求都需要的基础条件之一,不过有些情况会将url写死。
    method 是请求的方法;
    param 是请求的参数,也是最核心的部分。可以上传的包括字典、数组、字符串等。
    其余的参数可以根据需求进行更改,如果是图片或者文件或者其他的,也可以增加image等参数。

    其次是 BaseEngine 的实现

    /**
     基础请求
     */
    @interface BaseEngine : NSObject <NetClientDelegate>
    /// 成功回调
    @property (nonatomic, strong) void (^success)(NSDictionary* dict);
    /// 失败回调
    @property (nonatomic, strong) void (^fail)(NSDictionary* dict);
    /// 数据任务
    @property (nonatomic, strong) NSURLSessionDataTask *task;
    /// 接口配置
    @property (nonatomic, strong) BaseAPIConfig *config;
    
    #pragma mark- method
    /**
     上传并返回数值
     */
    - (void)startRequestWithConfig:(BaseAPIConfig *)config
                     successBlock:(void(^)(NSDictionary* dict))successBlock
                        failBlock:(void(^)(NSDictionary* dict))failBlock;
    
    /**
     上传并返回数值
     */
    - (void)startRequestWithConfig:(BaseAPIConfig *)config
                      successBlock:(void(^)(NSDictionary* dict))successBlock;
    
    /**
     取消任务
     */
    - (void)cancleTask;
    @end
    
    
    #import "BaseEngine.h"
    
    @implementation BaseAPIConfig
    @end
    
    @implementation BaseEngine
    
    #pragma mark- <NetClientDelegate>
    - (void)netClientSuccess:(NSDictionary *)successDict WithTask:(NSURLSessionDataTask *)task {
        self.task = nil;
        if (self.success) {
            self.success(successDict);
        }
    }
    
    - (void)netClientFail:(NSDictionary *)failDict WithTask:(NSURLSessionDataTask *)task {
        self.task = nil;
        if (self.fail) {
            self.fail(failDict);
        }
    }
    
    #pragma mark- public method
    - (void)cancleTask {
        if (self.task && [self.task respondsToSelector:@selector(cancel)]) {
            [[NetClient shareNetClient] cancleTask:self.task];
            self.task = nil;
        }
        
    }
    
    - (void)startRequestWithConfig:(BaseAPIConfig *)config
                      successBlock:(void(^)(NSDictionary* dict))successBlock {
        [self startRequestWithConfig:config successBlock:successBlock failBlock:nil];
    }
    
    - (void)startRequestWithConfig:(BaseAPIConfig *)config
                     successBlock:(void(^)(NSDictionary* dict))successBlock
                        failBlock:(void(^)(NSDictionary* dict))failBlock {
        self.success = successBlock;
        self.fail = failBlock;
        self.task = [[NetClient shareNetClient] postToMethod:config.method WithDict:config.param delegate:self];
    }
    @end
    
    

    这是最基础的实现,实现的是普通的请求、也可以单独使用。
    处理了以下几件事情:

    1. config进行解析,并传到client中进行处理。
    2. 将接口的回调进行处理,并判断通过block返回到使用层。
    3. 允许使用层取消任务。

    其他的几种分类都是为了实现不同方向的功能,在base之上做的修改。

    部分分类功能实现

    // 数据获取
    // DownLoadEngine
    
    #pragma mark- public method
    - (void)startRequestWithConfig:(BaseAPIConfig *)config
                      successBlock:(void(^)(NSDictionary* dict))successBlock
                         failBlock:(void(^)(NSDictionary* dict))failBlock {
        // 只保存一次的task
        if (self.task && [self.task respondsToSelector:@selector(cancel)]) {
            [self.task cancel];
        }
        
        [super startRequestWithConfig:config successBlock:successBlock failBlock:failBlock];
    }
    
    // 数据上传
    // UpLoadEngine
    
    - (void)cancleTask {
        return;
    }
    
    + (void)startRequestWithConfig:(BaseAPIConfig *)config
                      successBlock:(void(^)(NSDictionary* dict))successBlock {
        
        [[UploadEngine new] startRequestWithConfig:config successBlock:successBlock failBlock:nil];
    }
    
    + (void)startRequestWithConfig:(BaseAPIConfig *)config
                      successBlock:(void(^)(NSDictionary* dict))successBlock
                         failBlock:(void(^)(NSDictionary* dict))failBlock {
        [[UploadEngine new] startRequestWithConfig:config successBlock:successBlock failBlock:failBlock];
    }
    
    // 多次请求 Engine
    // MultipleEngine
    
    #import "MultipleEngine.h"
    
    @implementation MultipleEngine
    
    #pragma mark- <NetClientDelegate>
    - (void)netClientSuccess:(NSDictionary *)successDict WithTask:(NSURLSessionDataTask *)task {
        if ([self.tasksArray containsObject:task]) {
            [self.tasksArray removeObject:task];
        }
        
        if (self.success) {
            self.success(successDict);
        }
    }
    
    - (void)netClientFail:(NSDictionary *)failDict WithTask:(NSURLSessionDataTask *)task {
        if ([self.tasksArray containsObject:task]) {
            [self.tasksArray removeObject:task];
        }
        if (self.fail) {
            self.fail(failDict);
        }
    }
    #pragma mark- public method
    - (void)cancleAllTask {
        for (NSURLSessionDataTask *task in self.tasksArray) {
            [[NetClient shareNetClient] cancleTask:task];
        }
        [self.tasksArray removeAllObjects];
    }
    
    - (void)cancleTaskAtIndex:(NSInteger)index {
        if (index >= self.tasksArray.count) {
            return;
        }
        [[NetClient shareNetClient] cancleTask:self.tasksArray[index]];
        [self.tasksArray removeObjectAtIndex:index];
    }
    
    - (void)cancleTask {
        if (self.task && [self.task respondsToSelector:@selector(cancel)]) {
            [[NetClient shareNetClient] cancleTask:self.task];
            self.task = nil;
            [self.tasksArray removeObject:self.task];
        }
        
    }
    - (void)startRequestWithConfig:(BaseAPIConfig *)config
                      successBlock:(void(^)(NSDictionary* dict))successBlock
                         failBlock:(void(^)(NSDictionary* dict))failBlock {
        // 只保存一次的task
        [super startRequestWithConfig:config successBlock:successBlock failBlock:failBlock];
        [self.tasksArray addObject:self.task];
    }
    
    #pragma mark - getter/setter
    - (NSMutableArray *)tasksArray {
        if (!_tasksArray) {
            _tasksArray = [NSMutableArray array];
        }
        return _tasksArray;
    }
    @end
    
    

    多次请求的修改的比较多,原因是他需要从单个任务转换为任务数组,所有跟任务有关的都需要重写导致的。

    至此,大致的Engine功能已经实现。

    相关文章

      网友评论

      • coderhlt:大神,BaseAPIConfig 是方法接口配置的参数,后面回根据需求或者分类不同而增加或减少。将参数提取出来单独归类是为了让方法的参数减少,并且在以后增加参数的时候,不需要增加方法,只需修改原先方法即可。这句话怎么理解?能不能举个例子
        3697d6c42285:如果后期产品要求部分的接口需要进行缓存,不使用 BaseAPIConfig 的情况下需要做的改变有:
        1. 对应接口的实现方法中的接口名与内容(.m 文件)
        2. 对应接口的声明方法中的接口名(.h 文件)
        3. 调用对应接口的地方中的接口名与参数
        如果是 BaseAPIConfig 的话,需要做的改变有:
        1. BaseAPIConfig 中增加一个 cachePolicy 的参数。
        2. 对应接口的实现方法中的内容(.m 文件)
        3. 调用对应接口的地方中的 BaseAPIConfig 增加一个参数

        如果愿意在 Client 层中拆解 BaseAPIConfig 的话,第二点的改变都可以忽略。

        可以看出来的是,使用 BaseAPIConfig 之后,需要修改的地方,从1.n个 2.n个 3.xn个 变为1. 1个 2. xn 个
        且许多的时候x = 1

      本文标题:iOS网络层设计-Engine 实现

      本文链接:https://www.haomeiwen.com/subject/eiuxxxtx.html