这周主要在做网络请求的重构,在参考了很多开源的项目之后,做了一个基本的Demo。本文主要讲一下基本的使用方法,不涉及原理。
###背景
参考的项目有
- Mantle:模型层的的封装框架,解决了json转object的问题。
- YTKNetwork:网络请求的封装,基于AFNetworking,提供了普通请求,批量请求和依赖请求的处理。回调方法支持block和delegate两种模式。
用法
如何创建一个请求
程序启动完成后先配置一下baseUrl:1
2LCNetworkConfig *config = [LCNetworkConfig sharedInstance];
config.baseUrl = @"http://;
创建请求首先要继承一个请求类,并声明初始化方法,初始化方法里面的参数就是请求要用到的参数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52//.h文件
@interface UserLoginApi : LCRequest
- (id)initWithLoginName:(NSString *)loginName
password:(NSString *)password;
@end
//.m文件
@implementation UserLoginApi {
NSString *_loginName;
NSString *_password;
}
//初始化方法
- (id)initWithLoginName:(NSString *)loginName
password:(NSString *)password
{
self = [super init];
if (self) {
_loginName = loginName;
_password = password;
}
return self;
}
//请求的api,必须实现,如果有path类型的参数,需要从初始化方法里面把参数传进来,然后在这里拼装
- (NSString *)requestUrl {
return @"/login";
}
//请求方法,必须实现
- (LCRequestMethod)requestMethod {
return LCRequestMethodPost;
}
//请求参数合成,如果没有请求参数,也可以不实现
- (id)requestArgument {
NSString* tokenId = [USER_DEFAULT objectForKey:USERDEFAULTS_KEY_TOKENID];
NSString* clientId = [USER_DEFAULT objectForKey:USERDEFAULTS_KEY_REGISTERID];
return @{
@"loginName": _loginName,
@"password": _password,
@"source": @"iphone",
@"sign": @"ios",
@"versionNo": [LCSystemUtil appVersion],
@"iosTokenId": [LCStringUtil safeString:tokenId],
@"clientId": [LCStringUtil safeString:clientId]
};
}
@end
实现了请求的Api对象之后,就可以发送请求了,发送请求有两种方式:Block和Delegate:
Block方式:1
2
3
4
5
6CityQueryApi* api = [[CityQueryApi alloc] init];
[api startWithCompletionBlockWithSuccess:^(LCBaseRequest *request) {
} failure:^(LCBaseRequest *request) {
}];
Delegate方式:1
2
3
4
5
6
7
8
9
10
11CityQueryApi* api = [[CityQueryApi alloc] init];
api.delegate = self;
[api start];
- (void)requestFinished:(LCBaseRequest *)request
{
}
- (void)requestFailed:(LCBaseRequest *)request
{
}
如果一个页面只有一个请求,我觉得用Block比较直观,回调代码就在请求边上;如果有多个请求,用Delegate便于管理,因为回调处理代码都集中在一个地方。
######json转Model
json转Model使用了Mentle。原来转换起来比较麻烦,一是不能自定义属性名,接口返回json的key是什么,我们的属性就是什么;二是如果返回的对象是多层的,就需要手动的一层层解包,比较麻烦。
而Mentle完全解决了这些问题,并且提供了更多的功能(序列化什么的)。
首先,我们建立一个模型类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37json文件
{
nickName = nmj;
phone = 18512553387;
photoUrl = "<null>";
state = "<null>";
userId = 705363918947328;
}
//.h文件
@interface LoginUserModel : MTLModel <MTLJSONSerializing>
@property (nonatomic,strong) NSNumber *userId;
@property (nonatomic,copy) NSString *phone;
@property (nonatomic,copy) NSString *nickName;
@property (nonatomic,copy) NSString *avatarUrl;
@property (nonatomic,copy) NSString *loginState;
@end
//.m文件
@implementation LoginUserModel
//此方法必须实现,用来标记本地属性名和接口key之间的匹配
//如果属性名和接口key完全一致,则返回nil,但方法一定要写。
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{
@"avatarUrl": @"photoUrl",
@"loginState": @"state"
};
}
@end
然后在请求的回调里面获得model1
2NSError *error = nil;
LoginUserModel* model = [MTLJSONAdapter modelOfClass:LoginUserModel.class fromJSONDictionary:request.responseJSONObject error:&error];
如果是返回嵌套的对象,只需要增加一个方法,可以在CityGroupModel里面查到,它里面cityList对应的是一个数组,数组里面的每一个对象都是CityModel,Mantle会递归的进行解析,不用我们操心。1
2
3
4+ (NSValueTransformer *)cityListJSONTransformer
{
return [NSValueTransformer mtl_JSONArrayTransformerWithModelClass:CityModel.class];
}
HUD
HUD以前写起来比较麻烦,所以我把HUD的展示、消失、错误提示封装在请求里面了:一共两个属性,一个方法。1
2
3
4
5
6
7
8//是否展示HUD
@property (nonatomic,assign) BOOL showHUD;
//hud的文字
@property (nonatomic,copy) NSString* HUDText;
//显示错去消息的方法
- (void)showHUDError:(NSString*)msg;
如果不需要显示HUD,那么请求的时候什么也不用做,否则需要设置以上两个属性。如果请求出错需要提示的话,就在failure的block里面提示一下。1
2
3
4
5
6
7
8AACoinExchangeCodeApi* api = [[AACoinExchangeCodeApi alloc] initWithPayer:[UserInfoEntity shareEntity].phone tradeType:@"1" accType:accType amount:amount];
api.showHUD = YES;
api.HUDText = NSLocalizedString(@"Obtaining verification code", nil);
[api startWithCompletionBlockWithSuccess:^(LCBaseRequest *request) {
[self.getCodeButton beginCountDown];
} failure:^(LCBaseRequest *request) {
[request showHUDError:request.errorMessage];
}];