坚持 成长 每日一篇
OC的成员变量和属性
成员变量:就是定义了一个类的全局变量(不直接被外部访问,只能通过方法读或写)
属性:提供了get和set的成员变量。(直接能被外部读写,其实就是能通过.调用法读或写)
由此可知:在OC里面一个属性是和一个成员变量密切相关联的。当我们默认声明一个属性如果没有关联相应的成员变量会默认生成一个以下划线开头+属性名的成员变量。
成员变量操作函数
Ivar是成员变量结构体objc_ivar指针其定义如下
typedef struct objc_ivar *Ivar;
objc_ivar结构体定义如下:
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}
对该结构体的操作函数我们用ivar开头
//获取成员变量名
const char * ivar_getName ( Ivar v );
//获取成员变量类型编码
const char * ivar_getTypeEncoding ( Ivar v );
//获取成员变量的偏移量
ptrdiff_t ivar_getOffset ( Ivar v );
获取类中指定名称实例成员变量的信息
这个函数能够获取父类以上类定义的所有成员变量
Ivar class_getInstanceVariable ( Class cls, const char *name );
获取类成员变量的信息
OC似乎没有类成员变量,这个函数目前还不知道怎么用
Ivar class_getClassVariable ( Class cls, const char *name );
添加成员变量
BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
注意:不管是系统库提供的提供的类,还是我们自定义的类,都无法动态添加成员变量。但如果我们通过运行时来创建一个类的话,又应该如何给它添加成员变量呢?这时我们就可以使用class_addIvar函数了。不过需要注意的是,这个方法只能在objc_allocateClassPair函数与objc_registerClassPair之间调用。
获取整个成员变量列表
Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
注意:返回的列表不包含父类的成员变量和属性。
例子:
unsigned int outCount = 0;
Ivar *vars = class_copyIvarList([self class], &outCount); // 获取到所有的成员变量列表
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
// 遍历所有的成员变量
for (int i = 0; i < outCount; i++) {
Ivar ivar = vars[i]; // 取出第i个位置的成员变量
const char *propertyName = ivar_getName(ivar); // 获取变量名
const char *propertyType = ivar_getTypeEncoding(ivar); // 获取变量类型
NSString *propertyNameString = [NSString stringWithUTF8String:propertyName];
NSString *propertyTypeString = [NSString stringWithUTF8String:propertyType];
[dic setValue:propertyTypeString forKey:propertyNameString];
}
属性操作
objc_property_t
objc_property_t是表示Objective-C声明的属性的类型,其实际是指向objc_property结构体的指针。
注意:这里的objc_property在库中没有找到定义,网上很多资料把objc_property_attribute_t当作objc_property结构体定义。但是objc_property_attribute_t其实是保存属性的一些其他信息如关联的成员变量,类型,引用类型等。
typedef struct objc_property *objc_property_t;
下面是objc_property_attribute_t定义:
typedef struct {
const char *name; /**< The name of the attribute */
const char *value; /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
获取指定的属性
objc_property_t class_getProperty ( Class cls, const char *name );
获取属性列表
这里获取属性的列表是不获取父类的属性,只获取自身属性列表。
objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
//属性操作
//cout用于保存取出了多少属性
unsigned int outCount = 0;
objc_property_t * properties = class_copyPropertyList([Person class], &outCount);
for (int i = 0; i < outCount; i++)
{
objc_property_t property = properties[i];
NSLog(@"property's name: %s", property_getName(property));
}
free(properties);//最后必须用free释放
为类添加属性
感觉这个方法好鸡肋,成功添加了属性但是不能用点调用法调用,还是用关联对象比较好用一点。
BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
例子
//给已经有的Person类添加属性littleName。
objc_property_attribute_t type = { "T", "@\"NSString\"" };//属性类型为NSString
objc_property_attribute_t ownership = { "C", "copy" }; // C = copy
objc_property_attribute_t backingivar = { "V", "_littleName" };//_littleName为Person类的全局变量,这里是让新属性与之关联
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
class_addProperty([Person class], "littleName", attrs, 3);
//验证是否添加成功
objc_property_t pt = class_getProperty([Person class], "littleName");
NSLog(@"property's name: %s", property_getName(pt));
NSLog(@"property'attribute:%s",property_getAttributes(pt));
NSLog(@"property'release:%s",property_copyAttributeValue(pt, "C"));
NSLog(@"property'type:%s",property_copyAttributeValue(pt, "T"));
NSLog(@"property'value:%s",property_copyAttributeValue(pt, "V"));
//之后我们可以用KVC操作这个属性
替换类的属性
void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
获取属性名
const char * property_getName ( objc_property_t property );
获取属性特性描述字符串
const char * property_getAttributes ( objc_property_t property );
获取属性中指定的特性
char * property_copyAttributeValue ( objc_property_t property, const char *attributeName );
实例:
NSLog(@"property'type:%s",property_copyAttributeValue(property, "T"));//"T"表示获取该属性的类型
NSLog(@"property'value:%s",property_copyAttributeValue(property, "V"));//"V"表示获取该属性关联的成员变量
获取属性的特性列表
objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount );
注意:
1.property_copyAttributeValue函数,返回的char *在使用完后需要调用free()释放
2. property_copyAttributeList函数,返回值在使用完后需要调用free()释放。
3. 获取属性列表其实是获取的属性名是不带下划线的属性名。所以如果想很好的遍历属性名可以通过获取属性列表函数。