一耐量、前言
最近一段時(shí)間盒延,想著封裝一套網(wǎng)絡(luò)庫缩擂,在查資料時(shí)看到了YTKNetwork
,下載地址添寺,它基本包含的網(wǎng)絡(luò)請(qǐng)求的所有功能胯盯,而且在GitHub
上的星星數(shù)也都有了5k+了,我就仔細(xì)的看了看计露,嗯博脑,真香憎乙,基本上能用的功能全都有了!越看越想把自己工程里的網(wǎng)絡(luò)庫給換掉(自己封裝的AFNetworking)叉趣,但又發(fā)現(xiàn)了YTKNetwork
的用法跟我項(xiàng)目中本身有點(diǎn)不兼容泞边,于是乎我就想把它再次封裝一下,畢竟按照它提供的用法疗杉,一個(gè)接口就得有一個(gè)對(duì)應(yīng)的類來控制阵谚,小業(yè)務(wù)量的App還好,但是大項(xiàng)目豈不是要?jiǎng)?chuàng)建一堆的接口類烟具,我想應(yīng)該有不少小伙伴有同樣的問題梢什,伴隨著這個(gè)問題為出發(fā)點(diǎn),開始了再次封裝的嘗試朝聋。
二嗡午、思路
一個(gè)接口由一個(gè)類來控制,emm...冀痕,這是要解決的最重要的一個(gè)問題荔睹。而我要做的是由一個(gè)類來控制所有接口孔飒。首先我想到的就是寫一個(gè)接口類师抄,然后每個(gè)請(qǐng)求對(duì)應(yīng)接口類里的一個(gè)方法策泣,然后再調(diào)用YTKNetwork
來轉(zhuǎn)發(fā)淤毛。其它用法要盡量不改變YTKNetwork
宅此,以避免因?yàn)樵俜庋b原因而導(dǎo)致YTKNetwork
內(nèi)部邏輯的bug秋秤。
三椭符、開始搬磚
1.解決YTKNetwork
所有參數(shù)都是通過方法來傳遞
在官方示例中薯演,我們可以看到跟伏,方法請(qǐng)求的地址(后綴地址)丢胚、請(qǐng)求參數(shù)等都只能通過重寫- (NSString *)requestUrl
與- (nullable id)requestArgument
,我在這里的解決思路是寫一個(gè)YTKRequest
的分類受扳,然后再添加兩個(gè)屬性fUrl
携龟、param
,然后分別在兩個(gè)方法返回這兩個(gè)屬性值勘高。
//
// 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, ¶mKey, param, OBJC_ASSOCIATION_COPY);
}
- (NSDictionary *)param {
return objc_getAssociatedObject(self, ¶mKey);
}
pragma mark - 重寫YTKRequest方法
- (NSString *)requestUrl {
return self.fUrl;
}
- (nullable id)requestArgument {
return self.param;
}
- (NSTimeInterval)requestTimeoutInterval {
//超時(shí)時(shí)間
return 10;
}
- (nullable NSDictionary<NSString *, NSString *> *)requestHeaderFieldValueDictionary {
return 請(qǐng)求頭;
}
2.數(shù)據(jù)傳遞
我們封裝了YTKNetwork
那請(qǐng)求回來的數(shù)據(jù)也在封裝的類里峡蟋,解決數(shù)據(jù)傳遞,回傳給需要用到的地方华望,在這個(gè)分類里蕊蝗,使用了block
typedef void(^RequestResult)(BOOL isSuccess, id object);
@property (nonatomic, copy) RequestResult resultBlock; //數(shù)據(jù)傳遞
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.GET
與POST
請(qǐng)求處理
官方示例中,請(qǐng)求發(fā)送的是GET
還是POST
需要通過- (YTKRequestMethod)requestMethod
來指定赖舟,這里我們也可以參考上面的方法
@property (nonatomic, copy) NSNumber *requestType; //請(qǐng)求類型 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
對(duì)象
基本上需要用到的參數(shù)及方法都準(zhǔn)備好了蓬戚,剩下的就是將生成YTKRequest
對(duì)象并將對(duì)應(yīng)的屬性賦值,這里我添加了一個(gè)類方法來實(shí)現(xiàn)
- (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.接口類的實(shí)現(xiàn)
接口類的實(shí)現(xiàn)部份比較簡(jiǎn)單宾抓,沒什么可說的子漩,就是寫上對(duì)應(yīng)的Get
和Post
的調(diào)取方法豫喧,聲明一個(gè)代理,方便通知請(qǐng)求開始
幢泼、請(qǐng)求成功
和請(qǐng)求失敗
的三種情況紧显,然后子類繼承這個(gè)類,子類主要就是做一個(gè)接口對(duì)應(yīng)一個(gè)方法的實(shí)現(xiàn)
//
// 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
我這里簡(jiǎn)單寫了兩個(gè)例子缕棵,按現(xiàn)在這樣孵班,如果有新的接口,只需要在這里編寫對(duì)應(yīng)的調(diào)用方法就可以了
6.關(guān)于TEST_GET
和TEST_POST
在上面的接口類里挥吵,并沒有看到傳入的requestUrl
重父,而代替它的就是TEST_GET
和TEST_POST
,我在封裝的時(shí)候順便也把接口的聲明也做了處理忽匈,在FuHttpMethod
類里,小伙伴們?cè)谟玫臅r(shí)候矿辽,只需要在.h
文件里的枚舉添加一個(gè)case
丹允,在.m
里添加對(duì)應(yīng)的requestUrl
就可以了,至于其綁定邏輯我就不多介紹了袋倔,很簡(jiǎn)單雕蔽,想看的小伙伴可以看我在文章最后上傳的Demo。
typedef NS_ENUM(NSInteger, FuHttpType) {
FU_HTTP_BEGIN = -1,
TEST_POST, //測(cè)試POST請(qǐng)求
TEST_GET, //測(cè)試GET請(qǐng)求
FU_HTTP_END,
};
HTTP_INFO(@"test/post/requestUrl", TEST_POST);
HTTP_INFO(@"test/get/requestUrl", TEST_GET);
7.測(cè)試一下
在AppDelegate.m
的didFinishLaunchingWithOptions
方法里添加對(duì)YTKNetworkConfig
的配置宾娜,這里沒有改動(dòng)批狐,按照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.m
的viewDidLoad
里,先對(duì)接口類進(jìn)行初始化前塔,進(jìn)行測(cè)試
- (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(@"請(qǐng)求成功");
}else {
NSLog(@"請(qǐng)求失敗");
}
}];
}
- (void)getTest {
[[self.http http_testGet] setResultBlock:^(BOOL isSuccess, id _Nonnull object) {
if (isSuccess) {
NSLog(@"請(qǐng)求成功");
}else {
NSLog(@"請(qǐng)求失敗");
}
}];
}
當(dāng)你能看到控制臺(tái)有-[FuHttpRequest requestSuccess:request:] [Line 86] 數(shù)據(jù)信息:
這樣的字樣時(shí)就代表請(qǐng)求沒問題嚣艇,而后面就是對(duì)應(yīng)請(qǐng)求回來的json
,我在數(shù)據(jù)處理那寫了不少的邏輯华弓,基本上都與目前我做的項(xiàng)目有關(guān)食零,如果覺得與你的項(xiàng)目不太合適,小伙伴們可以自己稍加修改寂屏。
四贰谣、額外功能
在Json
轉(zhuǎn)Model
時(shí),我使用了YYModel
迁霎,相信很多小伙伴都給接口寫過對(duì)應(yīng)的Model
文件吱抚,工作量也不小,我在Demo
里添加了一個(gè)FuAnalysis
類考廉,用來做這個(gè)事秘豹,當(dāng)你的工程中沒有對(duì)應(yīng)的Model
時(shí),就會(huì)在控制臺(tái)輸出將要添加類的內(nèi)容芝此;如果存在憋肖,則使用YYModel
解析成對(duì)應(yīng)的對(duì)象因痛。文件名及相應(yīng)的類的命名都是以接口名為基礎(chǔ),例如:requestUrl
是abc/def
岸更,那么文件名就是DefModel
鸵膏,而里面的類的名字就是Def_Item
測(cè)試一下,寫一個(gè)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
---
工程里有對(duì)應(yīng)的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
測(cè)試成功怎炊!
有關(guān)代碼中出現(xiàn)的<id>
谭企,它是我們項(xiàng)目中requestUrl
需要拼接的參數(shù),例如在Post請(qǐng)求里评肆,test/post/123
债查,這樣的123
直接寫到requestUrl
里就不太對(duì)了,因此我加入了替換元素<id>
在請(qǐng)求發(fā)送之前再將requestUrl
替換好瓜挽。
最后盹廷,歡迎小伙伴在評(píng)論留言,喜歡的點(diǎn)個(gè)心久橙!