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];
// }
}