一步一步搭建自己的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)的功能。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容