美文网首页iOS 进阶
YTKNetwork再次封装

YTKNetwork再次封装

作者: Q海龙 | 来源:发表于2019-03-27 18:18 被阅读246次

一、前言

最近一段时间,想着封装一套网络库,在查资料时看到了YTKNetwork下载地址,它基本包含的网络请求的所有功能,而且在GitHub上的星星数也都有了5k+了,我就仔细的看了看,嗯,真香,基本上能用的功能全都有了!越看越想把自己工程里的网络库给换掉(自己封装的AFNetworking),但又发现了YTKNetwork的用法跟我项目中本身有点不兼容,于是乎我就想把它再次封装一下,毕竟按照它提供的用法,一个接口就得有一个对应的类来控制,小业务量的App还好,但是大项目岂不是要创建一堆的接口类,我想应该有不少小伙伴有同样的问题,伴随着这个问题为出发点,开始了再次封装的尝试。

二、思路

一个接口由一个类来控制,emm...,这是要解决的最重要的一个问题。而我要做的是由一个类来控制所有接口。首先我想到的就是写一个接口类,然后每个请求对应接口类里的一个方法,然后再调用YTKNetwork来转发。其它用法要尽量不改变YTKNetwork,以避免因为再封装原因而导致YTKNetwork内部逻辑的bug。

三、开始搬砖

1.解决YTKNetwork所有参数都是通过方法来传递

在官方示例中,我们可以看到,方法请求的地址(后缀地址)、请求参数等都只能通过重写- (NSString *)requestUrl- (nullable id)requestArgument,我在这里的解决思路是写一个YTKRequest的分类,然后再添加两个属性fUrlparam,然后分别在两个方法返回这两个属性值。

//
//  YTKRequest+FuHttp.h
//  FuHttpDemo
//
//  Created by 付海龙 on 2019/3/25.
//  Copyright © 2019 付海龙. All rights reserved.
//

#import "YTKRequest.h"

NS_ASSUME_NONNULL_BEGIN

@interface YTKRequest (FuHttp)
@property (nonatomic, copy) NSString *fUrl;             //requestUrl
@property (nonatomic, copy) NSDictionary *param;        //requestArgument
@end
//
//  YTKRequest+FuHttp.m
//  FuHttpDemo
//
//  Created by 付海龙 on 2019/3/25.
//  Copyright © 2019 付海龙. All rights reserved.
//

#import "YTKRequest+FuHttp.h"
#import "FuHttpMethod.h"
#import "YYKit.h"

@implementation YTKRequest (FuHttp)

static NSString *fUrlKey            = @"F_URL_KEY";
static NSString *paramKey           = @"PARAM_KEY";
static NSString *fuHttpTypeKey      = @"RESULT_BLOCK_KEY";

- (void)setFUrl:(NSString *)fUrl {
    objc_setAssociatedObject(self, &fUrlKey, fUrl, OBJC_ASSOCIATION_COPY);
}

- (NSString *)fUrl {
    return objc_getAssociatedObject(self, &fUrlKey);
}

- (void)setParam:(NSDictionary *)param {
    objc_setAssociatedObject(self, &paramKey, param, OBJC_ASSOCIATION_COPY);
}

- (NSDictionary *)param {
    return objc_getAssociatedObject(self, &paramKey);
}

pragma mark - 重写YTKRequest方法

- (NSString *)requestUrl {
    return self.fUrl;
}

- (nullable id)requestArgument {
    return self.param;
}

- (NSTimeInterval)requestTimeoutInterval {
    //超时时间 
    return 10;
}

- (nullable NSDictionary<NSString *, NSString *> *)requestHeaderFieldValueDictionary {
    return 请求头;
}

2.数据传递

我们封装了YTKNetwork那请求回来的数据也在封装的类里,解决数据传递,回传给需要用到的地方,在这个分类里,使用了block

typedef void(^RequestResult)(BOOL isSuccess, id object);

@property (nonatomic, copy) RequestResult resultBlock;  //数据传递
static NSString *resultBlockKey     = @"RESULT_BLOCK_KEY";

- (void)setResultBlock:(void (^)(BOOL, id _Nonnull))block {
    objc_setAssociatedObject(self, &resultBlockKey, block, OBJC_ASSOCIATION_COPY);
}

- (RequestResult)resultBlock {
    return objc_getAssociatedObject(self, &resultBlockKey);
}

3.GETPOST请求处理

官方示例中,请求发送的是GET还是POST需要通过- (YTKRequestMethod)requestMethod来指定,这里我们也可以参考上面的方法

@property (nonatomic, copy) NSNumber *requestType;      //请求类型 Get or Post
static NSString *requestTypeKey     = @"REQUEST_TYPE_KEY";

- (void)setRequestType:(NSNumber *)requestType
{
    objc_setAssociatedObject(self, &requestTypeKey, requestType, OBJC_ASSOCIATION_COPY);
}

- (NSNumber *)requestType
{
    return objc_getAssociatedObject(self, &requestTypeKey);
}

- (YTKRequestMethod)requestMethod {
    return self.requestType.integerValue;
}

4.获得YTKRequest对象

基本上需要用到的参数及方法都准备好了,剩下的就是将生成YTKRequest对象并将对应的属性赋值,这里我添加了一个类方法来实现

- (void)setRequestType:(NSUInteger)type param:(NSDictionary *)param requestType:(NSInteger)requestType replace:(NSString *)replace {
    NSString *url = [[FuHttpMethod sharedMethod] typeMethod:type];
    if ([url containsString:@"<id>"]) {
        if (replace.isNotBlank) {
            self.fUrl = [url stringByReplacingOccurrencesOfString:@"<id>"
                                                       withString:replace];
        }else {
            self.fUrl = [url stringByReplacingOccurrencesOfString:@"<id>"
                                                       withString:@""];
        }
    }else {
        self.fUrl = url;
    }
    self.param = param;
    self.FuHttpType = [NSNumber numberWithUnsignedInteger:type];
    self.requestType = [NSNumber numberWithInteger:requestType];
}

+ (YTKRequest *)getYTK:(NSUInteger)type param:(NSDictionary *)param requestType:(NSInteger)requestType replace:(NSString *)replace {
    YTKRequest *ytk = [[YTKRequest alloc] init];
    [ytk setRequestType:type
                  param:param
            requestType:requestType
                replace:replace];
    return ytk;
}

5.接口类的实现

接口类的实现部份比较简单,没什么可说的,就是写上对应的GetPost的调取方法,声明一个代理,方便通知请求开始请求成功请求失败的三种情况,然后子类继承这个类,子类主要就是做一个接口对应一个方法的实现

//
//  FuHttpRequest.h
//  FuHttpDemo
//
//  Created by 付海龙 on 2019/3/25.
//  Copyright © 2019 付海龙. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "YTKNetwork.h"
#import "FuHttpMethod.h"
#import "FuError.h"

NS_ASSUME_NONNULL_BEGIN

@class FuHttpRequest;
@protocol FuHttpRequestDelegate <NSObject>
@optional
- (void)httpStartRequest:(YTKBaseRequest *)requestObject;
- (void)httpFinishRequest:(YTKBaseRequest *)requestObject object:(id)object;
- (void)httpFailedRequest:(YTKBaseRequest *)requestObject error:(FuError *)error;
@end

@interface FuHttpRequest : NSObject
@property (nonatomic, weak) id<FuHttpRequestDelegate> delegate;
@property (nonatomic, assign) NSInteger requestTag;
+ (id)initWithDelegate:(id<FuHttpRequestDelegate>)delegate;
- (YTKRequest *)requestGet:(NSUInteger)type param:(nullable id)param replace:(nullable NSString *)replace;
- (YTKRequest *)requestPost:(NSUInteger)type param:(nullable id)param replace:(nullable NSString *)replace;;
@end
//
//  FuHttpInterface.h
//  FuHttpDemo
//
//  Created by 付海龙 on 2019/3/25.
//  Copyright © 2019 付海龙. All rights reserved.
//

#import "FuHttpRequest.h"
#import "YTKRequest+FuHttp.h"

NS_ASSUME_NONNULL_BEGIN

@interface FuHttpInterface : FuHttpRequest

- (YTKRequest *)http_testPost:(NSString *)str;
- (YTKRequest *)http_testGet;

@end

NS_ASSUME_NONNULL_END
//
//  FuHttpInterface.m
//  FuHttpDemo
//
//  Created by 付海龙 on 2019/3/25.
//  Copyright © 2019 付海龙. All rights reserved.
//

#import "FuHttpInterface.h"
#import "YYKit.h"

@implementation FuHttpInterface

- (YTKRequest *)http_testPost:(NSString *)str {
    NSDictionary *param = nil;
    if (str.isNotBlank) {
        param = @{@"query":str};
    }
    return [self requestPost:TEST_POST param:param replace:nil];
}

- (YTKRequest *)http_testGet {
    return [self requestGet:TEST_GET param:nil replace:nil];
}

@end

我这里简单写了两个例子,按现在这样,如果有新的接口,只需要在这里编写对应的调用方法就可以了

6.关于TEST_GETTEST_POST

在上面的接口类里,并没有看到传入的requestUrl,而代替它的就是TEST_GETTEST_POST,我在封装的时候顺便也把接口的声明也做了处理,在FuHttpMethod类里,小伙伴们在用的时候,只需要在.h文件里的枚举添加一个case,在.m里添加对应的requestUrl就可以了,至于其绑定逻辑我就不多介绍了,很简单,想看的小伙伴可以看我在文章最后上传的Demo。

typedef NS_ENUM(NSInteger, FuHttpType) {
    FU_HTTP_BEGIN = -1,
    
    TEST_POST,      //测试POST请求
    TEST_GET,       //测试GET请求
    
    FU_HTTP_END,
};
HTTP_INFO(@"test/post/requestUrl", TEST_POST);
HTTP_INFO(@"test/get/requestUrl", TEST_GET);

7.测试一下

AppDelegate.mdidFinishLaunchingWithOptions方法里添加对YTKNetworkConfig的配置,这里没有改动,按照YTKNetwork的用法来就好

    YTKNetworkConfig *config = [YTKNetworkConfig sharedConfig];
    /*
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"证书名" ofType:@"后缀"];
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    config.securityPolicy.allowInvalidCertificates = YES;
    config.securityPolicy.validatesDomainName = NO;
    config.securityPolicy.pinnedCertificates = [NSSet setWithObject:certData];
     */
    config.baseUrl = @"你的baseUrl";

ViewController.mviewDidLoad里,先对接口类进行初始化,进行测试

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.http = [[FuHttpInterface alloc] init];
    
//    [self postTest];
    [self getTest];
}

- (void)postTest {
    [[self.http http_testPost:@"abc"] setResultBlock:^(BOOL isSuccess, id  _Nonnull object) {
        if (isSuccess) {
            NSLog(@"请求成功");
        }else {
            NSLog(@"请求失败");
        }
    }];
}

- (void)getTest {
    [[self.http http_testGet] setResultBlock:^(BOOL isSuccess, id  _Nonnull object) {
        if (isSuccess) {
            NSLog(@"请求成功");
        }else {
            NSLog(@"请求失败");
        }
    }];
}

当你能看到控制台有-[FuHttpRequest requestSuccess:request:] [Line 86] 数据信息:这样的字样时就代表请求没问题,而后面就是对应请求回来的json,我在数据处理那写了不少的逻辑,基本上都与目前我做的项目有关,如果觉得与你的项目不太合适,小伙伴们可以自己稍加修改。

四、额外功能

JsonModel时,我使用了YYModel,相信很多小伙伴都给接口写过对应的Model文件,工作量也不小,我在Demo里添加了一个FuAnalysis类,用来做这个事,当你的工程中没有对应的Model时,就会在控制台输出将要添加类的内容;如果存在,则使用YYModel解析成对应的对象。文件名及相应的类的命名都是以接口名为基础,例如:requestUrlabc/def,那么文件名就是DefModel,而里面的类的名字就是Def_Item
测试一下,写一个Json

{"RC":1,"data":{"array":[{"name":"fu","address":"北京"},{"name":"hai","tel":8888},{"name":"long","is_working":true}]}}

FuAnalysis *analysis = [[FuAnalysis alloc] init];
id object = [analysis analysisData:@"abc/def" object:[jsonStr jsonValueDecoded]];
---

ClassName : DefModel 

.h文件

@interface Def_Array_Item : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *address;
@property (nonatomic, strong) NSNumber *tel;
@property (nonatomic, strong) NSNumber *is_working;
@end


@interface Def_Data_Item : NSObject
@property (nonatomic, strong) NSArray *array;
@end

@interface Def_Item : NSObject
@property (nonatomic, strong) NSNumber *RC;
@property (nonatomic, strong) Def_Data_Item *data;
@end


---

.m文件



@implementation Def_Array_Item

@end

@implementation Def_Data_Item

+ (NSDictionary *)modelContainerPropertyGenericClass {
   return @{
            @"array":[Def_Array_Item class],
           }
}

@end

@implementation Def_Item

@end


---

工程里有对应的Model文件

if ([object isKindOfClass:[Def_Item class]]) {
        Def_Item *item = (Def_Item *)object;
        [item.data.array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            Def_Array_Item *item = (Def_Array_Item *)obj;
            NSLog(@"%@", item.name);
        }];
    }
2019-03-27 17:46:25.116733+0800 FuYTKDemo[7311:458718] fu
2019-03-27 17:46:25.116862+0800 FuYTKDemo[7311:458718] hai
2019-03-27 17:46:25.116954+0800 FuYTKDemo[7311:458718] long

测试成功!

Demo下载地址

有关代码中出现的<id>,它是我们项目中requestUrl需要拼接的参数,例如在Post请求里,test/post/123,这样的123直接写到requestUrl里就不太对了,因此我加入了替换元素<id>在请求发送之前再将requestUrl替换好。

最后,欢迎小伙伴在评论留言,喜欢的点个心!

相关文章

  • YTKNetwork再次封装

    一、前言 最近一段时间,想着封装一套网络库,在查资料时看到了YTKNetwork,下载地址,它基本包含的网络请求的...

  • YTKNetwork集成教程以及相关问题思考

    YTKNetwork介绍 YTKNetwork 是猿题库 iOS 研发团队基于 AFNetworking 封装的 ...

  • 改造YTKNetWork(迁移到AF3.0)

    YTKNetWork是什么? YTKNetwork 是猿题库 iOS 研发团队基于 AFNetworking 封装...

  • YTKNetwork遇到的问题和总结

    YTKNetwork 是什么? YTKNetwork 是猿题库 iOS 研发团队基于AFNetworking封装的...

  • 小尝YTKNetwork

    一、什么是YTKNetwork YTKNetwork是一个基于AFNetworking的网络层封装。 二、包括那几...

  • YTKNetwork简单使用

    YTKNetwork是在AFNetworking的基础上进行封装。相信使用YTKNetwork的小伙伴,已经阅读了...

  • YTKNetwork补充用法

    YTKNetwork是基于AFNetworking网络封装,其主要的类如下: YTKBaseRequest YTK...

  • 对YTKNetwork的扩展

    YTKNetwork简介 YTKNetwork 的基本的思想是把每一个网络请求封装成对象。每一个请求都需要继承YT...

  • YTKNetwork解析

    YTKNetwork是猿题库 iOS 研发团队基于 AFNetworking 封装的 iOS 网络库,提供了更高层...

  • YTKNetwork源码解析

    YTKNetwork 是猿题库 iOS 研发团队基于 AFNetworking 封装的 iOS 网络库,其实现了一...

网友评论

    本文标题:YTKNetwork再次封装

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