一步一步搭建自己的iOS网络请求库(二)--封装接口

http://www.tuicool.com/articles/mQj2AfF


原文  http://lastday.github.io/ioshttplibrary/HttpLibrary2/

主题 iOS开发

一步一步搭建自己的iOS网络请求库(二)

大家好,我是LastDay,上一次分享了简单体验并且测试下一下NSURLSession。

我的博客地址:http://lastday.github.io

进行简单的封装

我们接下来将要加入动态的动态的HTTP参数(parameters)的功能,之后封装出我们自己的接口。

首先呢,我们先来对上一次的代码进行一次简单的封装,建立一个新的类LyNetWork,继承于NSObject类 。新建一个静态的request方法。将请求方式和URL传入

代码如下:

+(void)request :(NSString *)method URL:(NSString *)URL{

NSURL *url = [NSURL URLWithString:URL];

NSURLSession *session = [NSURLSession sharedSession];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

request.HTTPMethod = method;

NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *reponse,NSError *error){

//NSdata转String

NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"%@",string);

}];

[task resume];

}

OK

让我们在ViewController中进行一下测试,代码如下:

@IBAction func mainButtonBeTapped(sender: AnyObject) {

[LyNetWork request:@"GET" URL:@"http://cityuit.sinaapp.com/1.php"];

}

接下来运行一下:OK 依然显示我们正确的测试结果:succeed

使用Block处理请求返回值

简单的介绍下闭包(block),对于OC来说是一个新词,但不是新的概念,不是新的东西。学过Javascript的小伙伴对闭包应该不陌生吧~学过PHP的应该也不陌生,在PHP5.3版本以后也支持闭包, 也就是OC中所提到的Block。

现在对我们的request函数进行修改,LyNetWork.m代码如下:

+(void)requestMethod:(NSString *)method

URL:(NSString *)URL

success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success

failure:(void (^)(NSError *__nullable error))failure

{

NSURL *url = [NSURL URLWithString:URL];

NSURLSession *session = [NSURLSession sharedSession];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

request.HTTPMethod = method;

NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *response,NSError *error){

if (error) {

failure(error);

}else{

if (success) {

success(data,response);

}

}

}];

[task resume];

}

接下来修改ViewController中的函数调用,代码修改后如下:

- (IBAction)test:(id)sender {

[LyNetWork requestMethod:@"GET"

URL:@"http://cityuit.sinaapp.com/1.php"

success:^(NSData *data,NSURLResponse *response){

NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"%@",string);

}

failure:^(NSError *error){

NSLog(@"%@",error);

}];

}

测试结果依然返回succeed,测试结果正确

接下来进行我们最难处理的地方,增加parameters处理能力

我们先来处理GET方法吧

GET 方法下,params 在经过 url encode 之后直接附在 URL 末尾发送给服务器

类似于这个样子 GET /foo.php?first_name=John&last_name=Doe&action=Submit HTTP/1.1

修改我们的requestMethod方法,将其进行一下更改,引入parameters参数

+(void)requestMethod:(nullable NSString *)method

URL:(nullable NSString *)URL

parameters:(nullable id) parameters

success:(nullable void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success

failure:(nullable void (^)(NSError *__nullable error))failure;

接下来就该处理我们的parameters参数了

我们从AFNetworking中借鉴一下他的处理方案(其实这里本人就是模仿编写罢了)

我们新建一个类起名为LYURLRequestSerialization,在LYURLRequestSerialization.h添加一下方法

+(NSString *)LYQueryStringFromParameters:(NSDictionary *)parameters;

进入我们的LYURLRequestSerialization.m文件中,添加以下代码:

#import "LYURLRequestSerialization.h"

@interface LYURLRequestSerialization()

@property (readwrite, nonatomic, strong) id  value;

@property (readwrite, nonatomic, strong) id  field;

@end

@implementation LYURLRequestSerialization

- (id)initWithField:(id)field value:(id)value {

self = [super init];

if (!self) {

return nil;

}

self.field = field;

self.value = value;

return self;

}

#pragma mark -

FOUNDATION_EXPORT NSArray * LYQueryStringPairsFromDictionary(NSDictionary *dictionary);

FOUNDATION_EXPORT NSArray * LYQueryStringPairsFromKeyAndValue(NSString *key, id value);

+(NSString *)LYQueryStringFromParameters:(NSDictionary *)parameters {

NSMutableArray *mutablePairs = [NSMutableArray array];

for (LYURLRequestSerialization *pair in LYQueryStringPairsFromDictionary(parameters)) {

[mutablePairs addObject:[pair URLEncodedStringValue]];

}

return [mutablePairs componentsJoinedByString:@"&"];

}

NSArray * LYQueryStringPairsFromDictionary(NSDictionary *dictionary) {

return LYQueryStringPairsFromKeyAndValue(nil, dictionary);

}

NSArray * LYQueryStringPairsFromKeyAndValue(NSString *key, id value) {

NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];

if ([value isKindOfClass:[NSDictionary class]]) {

NSDictionary *dictionary = value;

for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {

id nestedValue = dictionary[nestedKey];

if (nestedValue) {

[mutableQueryStringComponents addObjectsFromArray:LYQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];

}

}

} else if ([value isKindOfClass:[NSArray class]]) {

NSArray *array = value;

for (id nestedValue in array) {

[mutableQueryStringComponents addObjectsFromArray:LYQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];

}

} else if ([value isKindOfClass:[NSSet class]]) {

NSSet *set = value;

for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {

[mutableQueryStringComponents addObjectsFromArray:LYQueryStringPairsFromKeyAndValue(key, obj)];

}

} else {

[mutableQueryStringComponents addObject:[[LYURLRequestSerialization alloc] initWithField:key value:value]];

}

return mutableQueryStringComponents;

}

static NSString * LYPercentEscapedStringFromString(NSString *string) {

static NSString * const kLYCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4

static NSString * const kLYCharactersSubDelimitersToEncode = @"!$&'()*+,;=";

NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];

[allowedCharacterSet removeCharactersInString:[kLYCharactersGeneralDelimitersToEncode stringByAppendingString:kLYCharactersSubDelimitersToEncode]];

static NSUInteger const batchSize = 50;

NSUInteger index = 0;

NSMutableString *escaped = @"".mutableCopy;

while (index < string.length) {

#pragma GCC diagnostic push

#pragma GCC diagnostic ignored "-Wgnu"

NSUInteger length = MIN(string.length - index, batchSize);

#pragma GCC diagnostic pop

NSRange range = NSMakeRange(index, length);

range = [string rangeOfComposedCharacterSequencesForRange:range];

NSString *substring = [string substringWithRange:range];

NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];

[escaped appendString:encoded];

index += range.length;

}

return escaped;

}

- (NSString *)URLEncodedStringValue {

if (!self.value || [self.value isEqual:[NSNull null]]) {

return LYPercentEscapedStringFromString([self.field description]);

} else {

return [NSString stringWithFormat:@"%@=%@", LYPercentEscapedStringFromString([self.field description]), LYPercentEscapedStringFromString([self.value description])];

}

}

@end

简单的说一下吧,以上的方法都是为了处理传入的NSDictonary参数,因为我们在使用的时候为了方便我们传入动态的parameters,所以他的的格式是这样的:

id parmenters = @{

@"value":@"LastDays",

};

将它处理后我们希望得到的样式应该是这样,对吧?

http:URL.php?value=LastDays

这个参数是一个动态的,我们不能确定里面到底有几组参数,而且还需要考虑的一个问题就是NSDictonary中嵌套NSDictonary的情况,我们处理这种问题的一个思想就是递归。从最里面开始处理。

OK,这样我们就实现了parameters处理能力

然后我们需要测试一下

为了进行测试我又重新更改了接口,提供了参数处理的能力,以下是新的接口:

http://cityuit.sinaapp.com/1.php  value=将要返回的值

更改下requestMethod方法

+(void)requestMethod:(NSString *)method

URL:(NSString *)URL

parameters:(id) parameters

success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success

failure:(void (^)(NSError *__nullable error))failure

{

NSString *newURL;

if ([method isEqual:@"GET"]) {

newURL = [[URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:parameters]];

NSLog(@"%@",newURL);

}

NSURL *url = [NSURL URLWithString:newURL];

NSURLSession *session = [NSURLSession sharedSession];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

request.HTTPMethod = method;

NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *response,NSError *error){

if (error) {

failure(error);

}else{

if (success) {

success(data,response);

}

}

}];

[task resume];

}

其中变化的地方:

if ([method isEqual:@"GET"]) {

newURL = [[URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:parameters]];

NSLog(@"%@",newURL);

}

以上代码的意思就是判断一下是否未GET请求,如果是的话将处理后的parameters加到尾部,以刚才的参数为例子,处理后的newURL为:http://cityuit.sinaapp.com/1.php?value=LastDays

也就是说返回值为LastDays

到ViewController.m中进行测试,测试代码如下:

- (IBAction)test:(id)sender {

id parmenters = @{

@"value":@"LastDays",

};

[LyNetWork requestMethod:@"GET"

URL:@"http://cityuit.sinaapp.com/1.php"

parameters:parmenters

success:^(NSData *data,NSURLResponse *response){

NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"%@",string);

}

failure:^(NSError *error){

NSLog(@"%@",error);

}];

}

ok返回结果为LastDays,成功添加入动态的动态的HTTP参数(parameters)的功能。

你可能感兴趣的:(一步一步搭建自己的iOS网络请求库(二)--封装接口)