这里记录一下自己在学习Runtime的心得,这里主要记录的是Ivar 和 Property 在获取类的属性和实例变量时候的区别。
class_copyIvarList 可以获取class的实例变量,包括属性,但是属性前加一个“ _ ”下划线。
class_copyPropertyList只会获取class的属性。
Ivar
定义:
typedef struct objc_ivar *Ivar
常用方法:
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
const char *ivar_getTypeEncoding(Ivar v)
const char *ivar_getName(Ivar v)
Property
定义:
typedef struct objc_property *objc_property_t;
常用方法:
const char *property_getName(objc_property_t property)
const char *property_getAttributes(objc_property_t property)
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
例子:
#import "RSBaseListViewController.h"
@interface MyOrderStatusListViewController : RSBaseListViewController
@property (nonatomic, strong) NSString *orderStatus;
@end
#import "objc/runtime.h"
@interface MyOrderStatusListViewController ()
{
NSMutableArray *dataArray;
}
@end
-(void)loadData
{
unsigned int ivarNum = 0;
Ivar *ivarList = class_copyIvarList([self class], &ivarNum);
for (int i = 0; i < ivarNum; i++) {
Ivar myIvar = ivarList[i];
const char *type = ivar_getTypeEncoding(myIvar);
NSString *stringType = [NSString stringWithCString:type encoding:NSUTF8StringEncoding];
NSLog(@"type %@", stringType);
const char *name = ivar_getName(myIvar);
NSString *stringName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
NSLog(@"name %@", stringName);
}
unsigned int propertyNum = 0;
objc_property_t *propertyList = class_copyPropertyList([self class], &propertyNum);
for (int j = 0; j < propertyNum; j++) {
objc_property_t myProperty = propertyList[j];
const char *propertyName = property_getName(myProperty);
NSString *stringPropertyName = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
NSLog(@"property Name %@", stringPropertyName);
const char *propertyAttribute = property_getAttributes(myProperty);
NSLog(@"property Attribute %s \n", propertyAttribute);
}
}
cmd 输出
[2508:1547221] type @"NSMutableArray"
[2508:1547221] name dataArray
[2508:1547221] type @"NSString"
[2508:1547221] name _orderStatus
[2508:1547221] property Name orderStatus
[2508:1547221] property Attribute T@"NSString",&,N,V_orderStatus
对比头文件,RSBaseListViewController.h里面定义了 orderStatus,属性 RSBaseListViewController.m 里面定义了 dataArray 实例变量,可以看出来,Ivar可以获取属性和实例变量,并且属性会有一个"_", Property可以获取我们定义的时候的参数。
学到这个东西可以干嘛了呢?
自动归档
@interface Person:NSObject
@property(nonautomic, strong) NSString *name;
@property(nonautomic, strong) NSString *sex;
@end
@implementation
-(void)encodeWithCoder:(NSCoder *)encoder
{
unsigned int count = 0;
Ivar *ivar = class_copyIvarList([self class] , &count);
for(int i = 0; i < count ; i++){
Ivar myVar = ivar[i];
const char *name = ivar_getName(myVar);
NSString *stringName = [NSString stringWithUTF8String:name];
[encode encodeObject:[self valueForKeyPath:stringName] forKey:stringName];
}
}
@end
自动实现NSCoping协议
- (id)copyWithZone:(nullable NSZone *)zone
{
UserEntity *entity = [[self class]allocWithZone:zone];
unsigned int propertyNum;
objc_property_t * propertys = class_copyPropertyList([self class], &propertyNum);
for (int i = 0; i < propertyNum; i++) {
objc_property_t property = propertys[i];
const char * propertyChar = property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:propertyChar];
id value = [self valueForKeyPath:propertyName];
if (value) {
[entity setValue:[self valueForKeyPath:propertyName] forKeyPath:propertyName];
}
}
free(propertys);
return entity;
}