一、基础知识
Method :成员方法
Ivar : 成员变量
二、常用方法
class_copyPropertyList : 获取属性列表
class_copyMethodList : 获取成员方法列表
class_copyIvarList:获取成员变量列表
ivar_getName:获取变量名
property_getName:获取属性名
使用示例:
1.获取成员变量列表
//1.获取变量list
unsigned int ivarCount = 0; //成员变量数
Ivar *ivarList = class_copyIvarList([self class], &ivarCount);//ivar数组
for (int i = 0; i < ivarCount; i++) {//遍历
Ivar ivar = ivarList[i]; //获取ivar
const char *name = ivar_getName(ivar);//获取变量名
NSString *key = [NSString stringWithUTF8String:name];
NSLog(@"%@", key);
}
free(ivarList);
2.获取属性列表
unsigned int count = 0;
objc_property_t *propertList = class_copyPropertyList([self class], &count);
for (int i = 0; i < count; i++) {
objc_property_t property = propertList[i];
const char *name = property_getName(property);
const char *attrs = property_getAttributes(property);
// property_copyAttributeValue(,) 第一个参数为objc_property_t,第二个参数"V"获取变量名,"T"获取类型
const char *value = property_copyAttributeValue(property, "V");
NSLog(@"name = %s, attrs = %s, value = %s", name, attrs, value);
}
free(propertList);
3.获取方法列表
unsigned int count = 0;
Method *methodList = class_copyMethodList([self class], &count);
for (int i = 0 ; i < count; i++) {
Method method = methodList[i];
SEL selector = method_getName(method);//方法入口
const char *sel_name = sel_getName(selector);
NSLog(@"方法名 %s", sel_name);
}
free(methodList);
实用
1.交换方法
新建分类,在实现+ (void)load 在加载时候交换
+ (void)load
{
//说明class_getInstanceMethod获取实例方法,class_getClassMethod获取类方法
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method method1 = class_getInstanceMethod(self, NSSelectorFromString(@"dealloc"));
Method method2 = class_getInstanceMethod(self, @selector(my_dealloc));
method_exchangeImplementations(method1, method2);
});
}
- (void)my_dealloc
{
NSLog(@"%@销毁了", self);
[self my_dealloc];
}
2、字典转模型
.h中
#import <Foundation/Foundation.h>
@protocol KeyValue <NSObject>
@optional
/**
* 数组中需要转换的模型类
*
* @return 字典中的key是数组属性名,value是数组中存放模型的Class(Class类型或者NSString类型)
*/
+ (NSDictionary *)objectClassInArray;
/**
* 将属性名换为其他key去字典中取值
*
* @return 字典中的key是属性名,value是从字典中取值用的key
*/
+ (NSDictionary *)replacedKeyFromPropertyName;
@end
@interface NSObject (Property) <KeyValue>
+ (instancetype)objectWithDictionary:(NSDictionary *)dictionary;
.m中的实现
#import "NSObject+Property.h"
#import <objc/runtime.h>
@implementation NSObject (Property)
+ (instancetype)objectWithDictionary:(NSDictionary *)dictionary
{
id obj = [[self alloc] init];
// 获取所有的成员变量
unsigned int count;
Ivar *ivars = class_copyIvarList(self, &count);
for (unsigned int i = 0; i < count; i++)
{
Ivar ivar = ivars[i];
// 取出的成员变量,去掉下划线
NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
NSString *key = [ivarName substringFromIndex:1];
id value = dictionary[key];
// 当这个值为空时,判断一下是否执行了replacedKeyFromPropertyName协议,如果执行了替换原来的key查值
if (!value)
{
if ([self respondsToSelector:@selector(replacedKeyFromPropertyName)])
{
NSString *replaceKey = [self replacedKeyFromPropertyName][key];
value = dictionary[replaceKey];
}
}
// 字典嵌套字典
if ([value isKindOfClass:[NSDictionary class]])
{
NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
NSRange range = [type rangeOfString:@"\""];
type = [type substringFromIndex:range.location + range.length];
range = [type rangeOfString:@"\""];
type = [type substringToIndex:range.location];
Class modelClass = NSClassFromString(type);
if (modelClass)
{
value = [modelClass objectWithDictionary:value];
}
}
// 字典嵌套数组
if ([value isKindOfClass:[NSArray class]])
{
if ([self respondsToSelector:@selector(objectClassInArray)])
{
NSMutableArray *models = [NSMutableArray array];
NSString *type = [self objectClassInArray][key];
Class classModel = NSClassFromString(type);
for (NSDictionary *dict in value)
{
id model = [classModel objectWithDictionary:dict];
[models addObject:model];
}
value = models;
}
}
if (value)
{
[obj setValue:value forKey:key];
}
}
// 释放ivars
free(ivars);
return obj;
}
@end
实用案例
subcategories 数组中装的SubCategoryModel类
+ (NSDictionary *)objectClassInArray
{
return @{ @"subcategories": @"SubCategoryModel"};
}
foodId 来替换关键字id
+ (NSDictionary *)replacedKeyFromPropertyName
{
return @{ @"foodId": @"id" };
}
/* 获取对象的所有属性 */
+(NSArray *)getAllProperties
{
u_int count;
// 传递count的地址过去 &count
objc_property_t *properties =class_copyPropertyList([self class], &count);
//arrayWithCapacity的效率稍微高那么一丢丢
NSMutableArray *propertiesArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++)
{
//此刻得到的propertyName为c语言的字符串
const char* propertyName =property_getName(properties[i]);
//此步骤把c语言的字符串转换为OC的NSString
[propertiesArray addObject: [NSString stringWithUTF8String: propertyName]];
}
//class_copyPropertyList底层为C语言,所以我们一定要记得释放properties
// You must free the array with free().
free(properties);
return propertiesArray;
}
/* 获取对象的所有方法 */
+(NSArray *)getAllMethods
{
unsigned int methodCount =0;
Method* methodList = class_copyMethodList([self class],&methodCount);
NSMutableArray *methodsArray = [NSMutableArray arrayWithCapacity:methodCount];
for(int i=0;i<methodCount;i++)
{
Method temp = methodList[i];
IMP imp = method_getImplementation(temp);
SEL name_f = method_getName(temp);
const char* name_s =sel_getName(method_getName(temp));
int arguments = method_getNumberOfArguments(temp);
const char* encoding =method_getTypeEncoding(temp);
NSLog(@"方法名:%@,参数个数:%d,编码方式:%@",[NSString stringWithUTF8String:name_s],
arguments,
[NSString stringWithUTF8String:encoding]);
[methodsArray addObject:[NSString stringWithUTF8String:name_s]];
}
free(methodList);
return methodsArray;
}
/* 获取对象的所有属性和属性内容 */
+ (NSDictionary *)getAllPropertiesAndVaules:(NSObject *)obj
{
NSMutableDictionary *propsDic = [NSMutableDictionary dictionary];
unsigned int outCount;
objc_property_t *properties =class_copyPropertyList([obj class], &outCount);
for ( int i = 0; i<outCount; i++)
{
objc_property_t property = properties[i];
const char* char_f =property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:char_f];
id propertyValue = [obj valueForKey:(NSString *)propertyName];
if (propertyValue) {
[propsDic setObject:propertyValue forKey:propertyName];
}
}
free(properties);
return propsDic;
}
@end
动态添加属性
1.第一种
#import "Person.h"
@interface Person (PersonExtention)
@property (copy, nonatomic) NSString *name;
-(void)saySex;
@end
#import "Person+PersonExtention.h"
#import <objc/runtime.h>
@implementation Person (PersonExtention)
//定义常量 必须是C语言字符串
static char *PersonNameKey = "PersonNameKey";
-(void)setName:(NSString *)name{
/*
OBJC_ASSOCIATION_ASSIGN; //assign策略
OBJC_ASSOCIATION_COPY_NONATOMIC; //copy策略
OBJC_ASSOCIATION_RETAIN_NONATOMIC; // retain策略
OBJC_ASSOCIATION_RETAIN;
OBJC_ASSOCIATION_COPY;
*/
/*
* id object 给哪个对象的属性赋值
const void *key 属性对应的key
id value 设置属性值为value
objc_AssociationPolicy policy 使用的策略,是一个枚举值,和copy,retain,assign是一样的,手机开发一般都选择NONATOMIC
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
*/
objc_setAssociatedObject(self, PersonNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString *)name{
return objc_getAssociatedObject(self, PersonNameKey);
}
-(void)saySex{
NSLog(@"%s----%@",__func__,self);
}
@end
2.第二种
@interface UIViewController (EZBackPop)
@property (nonatomic, assign) BOOL isAutorotate;
@end
- (BOOL)isAutorotate
{
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)setIsAutorotate:(BOOL)isAutorotate
{
objc_setAssociatedObject(self, @selector(isAutorotate), @(isAutorotate), OBJC_ASSOCIATION_ASSIGN);
}
3.第三种
@interface UIButton (sswAddType)
@property(nonatomic, assign) int type;
@end
- (void)setType:(int)type{
objc_setAssociatedObject(self, "type", @(type), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)type{
return [objc_getAssociatedObject(self, "type") intValue];
}