objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
函数是runtime
中的一个函数,用来 copy 一份类对象的属性列表,返回值为objc_property_t *
类型的数组。然后就可以遍历这个数组取出每个属性值。几乎每个字典转模型框架都需要这个函数。
- (NSDictionary *)properties_aps {
NSMutableDictionary *props = [NSMutableDictionary dictionary];
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList([self class], &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [[[NSString alloc] initWithCString:property_getName(property)] autorelease];
id propertyValue = [self valueForKey:(NSString *)propertyName];
if (propertyValue) [props setObject:propertyValue forKey:propertyName];
}
free(properties);
return props;
}
这段代码中就包含了取属性的函数:
objc_property_t *properties = class_copyPropertyList([self class], &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
}
objc_property_t *
类型的properties
数组,取出下标,得到的是objc_property_t
类型的数组元素。
这个写法突然感觉有些不解,因为如果我们用int
来代替objc_property_t
:
int main(int argc, const char * argv[]) {
int *arr = {1,2,3};
arr[1] = 10;
int a = arr[1];
NSLog(@"%d", a);
return 0;
}
这样显然是不行的,int *
只是一个指针,C语言中,数组的本质是指针加偏移量,所以当给arr[1]
赋值时,相当于是给arr
这个指针偏移了8bit,然而我们并没有为后面的地址开辟内存空间,自然就造成了EXC_BAD_ACCESS
错误。
那么,该怎么写成runtime里的那段代码一样type *
类型的foo
数组变量,可以用foo[1]
取得一个type
类型的数组元素呢?
所以我们要分析,上面那个int
的写法是怎么不对的。因为在给int *arr
初始化时,并没有开辟一个sizeof(int)*count
大小的内存空间。
之所以如果写成int arr[3]
就可以,是因为这么写,C语言数组的本质是就是指针加偏移量。初始化了一个int指针,而且给了3*sizeof(int)
大小的内存空间,返回了一个指针arr
。所以,我们可以手动做这个步骤:
typedef int integer;
typedef integer * integer_pointer;
integer_pointer * addIntegerToArr(integer_pointer p, ...) {
integer_pointer *result = nil;
if (p) {
va_list args;
int count = 1;
integer_pointer current;
va_start(args, p);
while ((current = va_arg(args, integer_pointer))) {
++count;
}
va_end(args);
result = (integer_pointer *)malloc((count) * sizeof(integer_pointer));
result[0] = p;
va_start(args, p);
current = va_arg(args, integer_pointer);
for (int i = 1; i < count; i++) {
result[i] = current;
}
va_end(args);
}
return (integer_pointer *)result;
}
int main(int argc, const char * argv[]) {
integer a = 10;
integer b = 11;
integer_pointer pa = &a;
integer_pointer pb = &b;
integer_pointer *r = addIntegerToArr(pa, pb);
integer_pointer num = r[1];
NSLog(@"%d", *num);
return 0;
}
里面真正关键的一句代码就是result = (integer_pointer *)malloc((count) * sizeof(integer_pointer));
,这样我们就开辟了一个内存空间,并且得到一个integer_pointer *
类型的指针,所以可以通过对这个指针的偏移,来操作这个空间中的integer_pointer
变量。
之所以result
看起来是一个数组,可以用result[i]
这种写法,就是因为上面的原因。
所以,还是要谨记,C语言中的数组,本质上就是指针加偏移。
虽然我们是iOS开发者,但是毕竟C语言不能放,闲来无事可以仿照runtime
中很多C语言特征的写法,来实现一些语言层面的学习。虽然上面所说的内容,对真正精通C/C++的高手来说,还是太幼稚了,但是,思考的过程还是非常有趣。况且,在上面这个练习中,还顺手学习了一下可变参数的内容。
并没什么太高的技术含量,所以,此篇算作闲情而已。
更多内容欢迎访问我的博客http://suntao.me