YTKNetwork再次封装

一、前言

最近一段时间,想着封装一套网络库,在查资料时看到了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替换好。

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342