YTK理解

作者: bliva | 来源:发表于2018-08-06 09:09 被阅读0次

    一、YTK的Git库地址

    https://github.com/yuantiku/YTKNetwork/blob/master/Docs/BasicGuide_cn.md
    里面有YTK的中文说明,以及一些场景的用法,下面我们来看一下我们项目的一些使用场景

    二、基类的封装

    1、我们现在所用的接口请求是在YTK的基础上在封装了一层(房信平台封装了2层,因为要加上缓存以及加密等逻辑),那房信平台的FangChaChaRequest来说,继承于EtopBaseRequest,EtopBaseRequest主要做了设置接口的请求方式(有两种请求方式,POST和GET,注上两者区别https://www.cnblogs.com/logsharing/p/8448446.html,一般都用POST(更安全));重写自定义请求头的方法,塞入请求头的样式;以及解析返回结果的格式(JSON,XML,Data三种,一般都用JSON);封装调用请求的方法;

    image.png
    image.png
    2、下面我们看FangChaChaRequest做了什么?
    (1)首先涉及加密的逻辑处理,我们要对接口的请求参数进行加密,这里的加密会每次根据App启动随机变成加密值,加密的代码附上如下图
    image.png
    (2)设置请求失败提示时间(一般都是15s)
    - (NSTimeInterval)requestTimeoutInterval {
    //    if (DEBUG) {
    //        return 5;
    //    }
        return 15;
    }
    

    (3)重写- (void)startWithCompletionHandlerWithSuccess:(nullable ETopRequestSuccessBlock)success failure:(nullable ETopRequestFailureBlock)failure方法,请求成功的时候先判断开没开起缓存,如果有先返回缓存数据,这里一定要注意的是如果用户开启了缓存,即使缓存成功,我们也需在重新调用一次请求方法,更新缓存,否则每次拿到的都是头一次缓存的结果;
    a、请求成功


    image.png

    b、请求失败,拿到错误信息,判断是否是证书错误


    image.png

    (4)特别注意的是因为我们对请求参数进行了加密,然后YTK的缓存是把请求参数当做Key,前面有提过APP启动的时候加密会随机,这个时候我们的缓存的Key变了,我们就拿不到上一次缓存数据的值,所以,我们加密后必须在FangChaChaRequest里面重写YTK的获取Key的- (id)cacheFileNameFilterForRequestArgument:(id)argument这个方法,返回我们未加密前的请求参数

    - (id)cacheFileNameFilterForRequestArgument:(id)argument {
        if ((NSNull *)self.unEncryptorArgument != [NSNull null] && self.unEncryptorArgument.count > 0) {
            return self.unEncryptorArgument;
        } else {
            return argument;
        }
    }
    

    三、应用场景

    1、缓存使用

    在上面封装完毕后,只需要在我们的API文件中,重写- (NSInteger)cacheTimeInSeconds这个方法,并设置你想要缓存的时间(一般我们返回最大值)

    - (NSInteger)cacheTimeInSeconds {
        return NSIntegerMax;
    }
    

    2、异步请求

    (1)YTK的异步请求适用于两个接口之间没什么依赖;但是YTK的异步请求会有一个接口请求失败,接口就返回失败;正常来说,逻辑也应该这么处理,虽然两个接口没有依赖,但是如果一个界面有两个接口,又是异步请求,如果不知道那个接口先回来,布局比较麻烦,所以还是一个接口接口失败直接失败处理比较好;最先我不会YTK的异步请求的时候写了一个非常low的请求方法(捂脸),block里面调用block,请求成功调用一次,失败在调用一次


    image.png

    所以使用YTK的异步请求后,我们只需要调用一个方法,也不需要写这么多回调的block


    image.png

    (2)值得注意的是我们也在YTK的异步请求YTKBatchRequest做了一层我们项目逻辑的封装FangChaChaBatchRequest,因为如果我们直接调用YTKBatchRequest,这个时候我们一些成功回调里面返回的其他状态码不会判断,所以我们要在YTK的基础上封装一层加上我们逻辑处理的基类

    - (void)startWithCompletionHandlerWithSuccess:(nullable ETopBatchCompletionBlock)success failure:(nullable ETopBatchCompletionBlock)failure {
        [super startWithCompletionBlockWithSuccess:^(YTKBatchRequest *_Nonnull batchRequest) {
            for (YTKRequest *request in batchRequest.requestArray) {
                id responseObjec = [request responseJSONObject];
                NSInteger statusCode = [responseObjec[@"StatsCode"] integerValue];
                statusCode = (statusCode == 0 ? [responseObjec[@"status"] integerValue] : statusCode);
                if (statusCode == SUCCEEDED_BatchRequest) {
                    if (success) {
                        success((ETopBatchRequest *)batchRequest);
                    }
                } else {
                    if (statusCode == LoginFailCodeType) {
                        // 清空用户信息
                        [LoginManager saveUserModel:nil];
                    } else if (statusCode == AuthorizationFailedCodeType) {
                        NSLog(@"重新获取token");
                        [[DDOAuthClient shareInstance] getTokenAndLoginWithSuccess:nil];
                    }
                    if (failure) {
                        NSString *message = request.responseObject[@"Message"];
                        message = message ?: request.responseObject[@"msg"];
                        failure((ETopBatchRequest *)batchRequest);
                    }
                }
            }        
        }
            failure:^(YTKBatchRequest *_Nonnull batchRequest) {
                if (failure) {
                    // 失败
                    NSString *description = batchRequest.failedRequest.error.localizedDescription;
                    description = [description stringByReplacingOccurrencesOfString:@"." withString:@""];
                    description = [description stringByReplacingOccurrencesOfString:@"。" withString:@""];
                    if (batchRequest.failedRequest.error.localizedRecoverySuggestion) { // 证书错误
                        NSData *errorData = [[NSData alloc] initWithData:[batchRequest.failedRequest.error.localizedRecoverySuggestion dataUsingEncoding:NSUTF8StringEncoding]];
                        NSDictionary *recoverySuggestion = [NSJSONSerialization JSONObjectWithData:errorData options:NSJSONReadingMutableLeaves error:nil];
                        if (recoverySuggestion) {
                            NSString *message = recoverySuggestion[@"Message"];
                            message = message ?: recoverySuggestion[@"msg"];
                            description = message;
                        }
                    }
                    failure((ETopBatchRequest *)batchRequest);
                }
            }];
    }
    

    3、同步请求

    (1)同步请求适用于两个接口直接存在依赖,第二个接口请求的参数必须从第一个接口请求成功后的结果而来,前面也提到过,我们请求的时候有自己的状态码逻辑处理,所以同理异步请求我们也需要做一层基于YTKChainRequest的封装;同步请求不像异步请求,它的返回回调是两个代理方法- (void)chainRequestFinished:(YTKChainRequest *)chainRequest(完成的代理方法),- (void)chainRequestFailed:(YTKChainRequest *)chainRequest failedBaseRequest:(YTKBaseRequest *)request (失败的代理方法),所以我们在封装的时候首页要遵循代理,设置代理为自己以及请求成功和失败的回调,在请求成功后我们返回请求成功的block,失败的时候判断失败的错误,并返回失败的回调
    a、初始化,遵循代理

    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.delegate = self;
        }
        return self;
    }
    

    b、调用父类的同步请求方法,回调请求数据

    - (void)addYTRequest:(ETopBaseRequest *)request callback:(nullable ETopChainCallback)callback{
        [super addRequest:request callback:^(YTKChainRequest * _Nonnull chainRequest, YTKBaseRequest * _Nonnull baseRequest) {
            if (callback) {
                callback((ETopChainRequest *)chainRequest,(ETopBaseRequest *)baseRequest);
            }
        }];
    }
    

    c、实现请求成功的代理方法,加上项目的状态码等逻辑判断,并且回调请求成功的数据

    - (void)chainRequestFinished:(YTKChainRequest *)chainRequest {
    
        for (YTKBaseRequest *request in chainRequest.requestArray) {
            id responseObjec = [request responseJSONObject];
            NSInteger statusCode = [responseObjec[@"StatsCode"] integerValue];
            statusCode = (statusCode == 0 ? [responseObjec[@"status"] integerValue] : statusCode);
            if (statusCode == SUCCEED_ChainRequest) {
                if (self.ChainRequestSuccessBlock) {
                    self.ChainRequestSuccessBlock((ETopChainRequest *)chainRequest);
                }
            } else {
                if (statusCode == LoginFailCodeType) {
                    // 清空用户信息
                    [LoginManager saveUserModel:nil];
                } else if (statusCode == AuthorizationFailedCodeType) {
                    NSLog(@"重新获取token");
                    [[DDOAuthClient shareInstance] getTokenAndLoginWithSuccess:nil];
                }
                if (self.ChainRequestFailureBlock) {
                    NSString *message = request.responseObject[@"Message"];
                    message = message ?: request.responseObject[@"msg"];
                    self.ChainRequestFailureBlock((ETopChainRequest *)chainRequest, message);
                }
            }
        }
    }
    

    b、实现请求失败的代理,判断是否是证书错误的逻辑判断,并且返回失败的数据和提示

    - (void)chainRequestFailed:(YTKChainRequest *)chainRequest failedBaseRequest:(YTKBaseRequest *)request {
        // 失败
        NSString *description = request.error.localizedDescription;
        description = [description stringByReplacingOccurrencesOfString:@"." withString:@""];
        description = [description stringByReplacingOccurrencesOfString:@"。" withString:@""];
        if (request.error.localizedRecoverySuggestion) { // 证书错误
            NSData *errorData = [[NSData alloc] initWithData:[request.error.localizedRecoverySuggestion dataUsingEncoding:NSUTF8StringEncoding]];
            NSDictionary *recoverySuggestion = [NSJSONSerialization JSONObjectWithData:errorData options:NSJSONReadingMutableLeaves error:nil];
            if (recoverySuggestion) {
                NSString *message = recoverySuggestion[@"Message"];
                message = message ?: recoverySuggestion[@"msg"];
                description = message;
            }
        }
        self.ChainRequestFailureBlock((ETopChainRequest *)chainRequest, description);
    }
    

    (2)具体使用方法
    请求数据,(两个接口直接一定具有依赖性,这里只是举例,其实举例的这两个接口没有啥依赖)


    image.png

    a、请求失败的处理


    image.png

    b、请求成功,UI布局


    image.png

    4、YTK的文件流上传功能

    我们可以通过重写constructingBodyBlock的方法,来实现上传(例如我们上传语音和图片),我们项目中的UploadFileAPI接口有用到

    - (AFConstructingBlock)constructingBodyBlock {
        return ^(id<AFMultipartFormData> formData) {
            for (UploadFileModel *model in _fileModelsArray) {
                [formData appendPartWithFileData:model.data name:model.fileName fileName:model.fileName mimeType:@""];
            }
        };
    }
    

    5、断点续传

    要启动断点续传功能,我们只需要覆盖resumableDownloadPath方法,指定断点续传时文件的存储路径即可,文件会被自动保存到此路径;(项目暂时没有用到,这里现附上YTK的用例,假设我们需要从服务器下载一张图片到本地)

    - (NSString *)resumableDownloadPath {
        NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString *cachePath = [libPath stringByAppendingPathComponent:@"Caches"];
        NSString *filePath = [cachePath stringByAppendingPathComponent:_imageId];
        return filePath;
    }
    
    

    总结

    YTK隔离出了业务逻辑层,一些小的方法比较省代码,会提高效率

    相关文章

      网友评论

          本文标题:YTK理解

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