iOS开发之利用iOS反射机制写网络请求类
iOS属性反射:说白了,就是将两个对象的所有属性,用动态的方式取出来,并根据属性名,自动绑值。(注意:对象的类,如果是派生类,就得靠其他方式来实现了,因为得到不该基类的属性。)
从一个NSDictionary->自定义实体类(此方式最最常用,如网络Json数据会组成NSDictionary。sqlite查询数据,可以用第三方组件组成NSDictionary)
直接上码,(这里码在NSObject类别中)
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> // 检测网络连接服务器地址 //#define HOST_NAME @"http://www.baidu.com" // 超时时间 static const NSInteger DEFAULT_TIMEOUT = 30; // 定义block类型 typedef void(^FinishBlock)(id result); // 请求成功 typedef void(^FailureBlock)(NSError *error);// 请求失败 typedef void(^SetParamsBlock)(void); // 设置参数d的block @interface LYSDataService : NSObject { NSMutableArray *_dataTasks; // 任务存储数组 } // 如果是id的参数我们给他一个规范_id // 网络请求参数配置 @property (nonatomic, strong) NSString *api_url; @property (nonatomic, strong) NSString *httpMethod; @property (nonatomic, assign) NSString *timeout; // 配置是否润许使用蜂窝数据(默认是润许的) @property (nonatomic, assign) BOOL allowsCellularAccess; // 是否润许多任务 @property (nonatomic, assign) BOOL isMoreDataTask; // 网络请求对象 @property (nonatomic, strong) NSURLSessionDataTask *dataTask; #pragma mark - 开始网络请求 - (void)requestDataWithParamsBlcok:(SetParamsBlock)paramsBlock FinishBlock:(FinishBlock)finishBlock failureBlock:(FailureBlock)failureBlock; @end
#import "LYSDataService.h" #import <objc/runtime.h> #import <CommonCrypto/CommonCrypto.h> @implementation LYSDataService - (void)dealloc { if (_isMoreDataTask == YES) { // 取消所有为完成任务 for (NSURLSessionDataTask *dataTask in _dataTasks) { [dataTask cancel]; } } else { [_dataTask cancel]; } } #pragma mark - 自定义初始化方法 - (instancetype)init { self = [super init]; if (self) { // 润许使用蜂窝数据 _allowsCellularAccess = YES; _httpMethod = @"GET"; // 1.初始化基本数据类型的值为:-100 // 01 获取当前类 Class myClass = [self class]; // 02 获取当前类中属性名字的集合 unsigned int count; objc_property_t *properties = class_copyPropertyList(myClass, &count); // 03 遍历所有的属性 for (int i = 0; i < count; i++) { // 获取当前属性的名字 objc_property_t property = properties[i]; const char * char_property_name = property_getName(property); // 如果获取到这个属性的名字 if (char_property_name) { // 转换成字符串对象 NSString *property_name = [[NSString alloc] initWithCString:char_property_name encoding:NSUTF8StringEncoding]; // 获取当前属性对应的内容 id value = [self valueForKey:property_name]; // 判断当前对象是数值对象 if ([value isKindOfClass:[NSValue class]]) { // 设置默认值:-100 [self setValue:@(-100) forKey:property_name]; } } } free(properties); } return self; } #pragma mark - 开始网络请求 - (void)requestDataWithParamsBlcok:(SetParamsBlock)paramsBlock FinishBlock:(FinishBlock)finishBlock failureBlock:(FailureBlock)failureBlock { // 1.取消之前的网络请求 if (_isMoreDataTask == NO) { [_dataTask cancel]; } else { if (_dataTasks == nil) { // 创建存储多任务数组 _dataTasks = [[NSMutableArray alloc] init]; } } // 现实加载进度 [UIApplication sharedApplication].networkActivityIndicatorVisible = YES ; // 2.添加请求对象参数配置设置block if (paramsBlock != nil) { paramsBlock(); } // 3.设置网络请求 // 判断请求方式 // 01 构建请求对象 NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] init]; [urlRequest setHTTPMethod:_httpMethod]; if (self.timeout == nil) { [urlRequest setTimeoutInterval:DEFAULT_TIMEOUT]; }else{ urlRequest.timeoutInterval = [self.timeout integerValue]; } urlRequest.allowsCellularAccess = self.allowsCellularAccess; NSString *urlString = _api_url; // 02 添加参数 if ([self.httpMethod caseInsensitiveCompare:@"GET"] == NSOrderedSame||[self.httpMethod caseInsensitiveCompare:@"DELETE"] == NSOrderedSame||[self.httpMethod caseInsensitiveCompare:@"PUT"] == NSOrderedSame||[self.httpMethod caseInsensitiveCompare:@"DEAD"] == NSOrderedSame) { // 03 如果是get方法(忽略大小写区比较) // 获取当前的参数 NSDictionary *attributes = [self getMyClassAttributeNameAndValue]; if (attributes.count > 0) { // 说明有参数 urlString = [NSString stringWithFormat:@"%@?",urlString]; } // 把参数拼接到路径的后面 for (int i=0; i<attributes.count; i++) { NSString *key = attributes.allKeys[i]; if (i==0) { urlString = [NSString stringWithFormat:@"%@%@=%@",urlString,key,attributes[key]]; }else{ urlString = [NSString stringWithFormat:@"%@&%@=%@",urlString,key,attributes[key]]; } } // 设置请求对象的URL地址 urlRequest.URL = [NSURL URLWithString:urlString]; } else if ([self.httpMethod caseInsensitiveCompare:@"POST"] == NSOrderedSame) { // 03 如果是POST请求 // 设置请求对象的URL地址 urlRequest.URL = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; // 获取当前的参数 NSDictionary *attributes = [self getMyClassAttributeNameAndValue]; // 把参数添加到请求体中 [urlRequest setHTTPBody:[self getDataStringWithParams:attributes]]; [urlRequest addValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; } // 03 创建网络会话对象 NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; config.allowsCellularAccess = self.allowsCellularAccess; NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:config]; // 04 开始创建网络任务对象 _dataTask = [urlSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ // 移除当前已经完成任务 if (_isMoreDataTask == YES) { [_dataTasks removeObject:_dataTask]; } if (error == nil) { if (data != nil) { // JSON解析 id result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; [urlSession invalidateAndCancel]; finishBlock(result); } else { [urlSession invalidateAndCancel]; finishBlock(data); } [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; } else { if (failureBlock) { [urlSession invalidateAndCancel]; failureBlock(error); } [UIApplication sharedApplication].networkActivityIndicatorVisible = NO ; } }); }]; // 把当前任务存储到多任务中 if (_isMoreDataTask == YES) { [_dataTasks addObject:_dataTask]; } // 05 开始执行任务 [_dataTask resume]; } // 获取当前对象已经设置内容的数据名字和对应的内容 - (NSMutableDictionary *)getMyClassAttributeNameAndValue { // 1.创建一个可变字典获取当前类的属性和内容 NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init]; // 2.获取当前类中所有属性名字的集合 // 01 获取当前类 Class myClass = [self class]; // 02 获取当前类中属性名字的集合 unsigned int count; objc_property_t *properties = class_copyPropertyList(myClass, &count); // 03 遍历所有的属性 for (int i = 0; i < count; i++) { // 获取当前属性的名字 objc_property_t property = properties[i]; const char * char_property_name = property_getName(property); // 如果获取到这个属性的名字 if (char_property_name) { // 转换成字符串对象 NSString *property_name = [[NSString alloc] initWithCString:char_property_name encoding:NSUTF8StringEncoding]; // 如果是id的参数我们给他一个明明规范_id if ([property_name hasPrefix:@"_"]) { property_name = [property_name substringFromIndex:1]; } // 获取当前属性对应的内容 id value = [self valueForKey:property_name]; if ([value isKindOfClass:[NSData class]] || (value != nil && [value intValue] != -100)) { [attributes setObject:value forKey:property_name]; } } } free(properties); return attributes; } #pragma mark - 把参数转换成二进制数据对象 - (NSData *)getDataStringWithParams:(NSDictionary *)params { NSData * jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil]; NSString * postString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSData * postData = [postString dataUsingEncoding:NSUTF8StringEncoding]; return postData; // // 01 遍历字典把字典里面的参数转换成字符串 // // 创建一个可变字符串 // NSMutableString *paramString = [[NSMutableString alloc] init]; // for (NSString *key in params) { // [paramString appendFormat:@"&%@=%@",key,params[key]]; // } // // if (paramString == nil) { // return nil; // } else { // return [[paramString substringFromIndex:1] dataUsingEncoding:NSUTF8StringEncoding]; // } }