举个简单的例子
[textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
[textField setValue:[UIFont boldSystemFontOfSize:16] forKeyPath:@"_placeholderLabel.font"];
_placeholderLabel的textColor属性是我们拿不到的。但是我们可以通过KeyValueCoding来进行操作。那怎么知道我们用的系统类里面有没有那个属性呢?
我的逻辑是先搞清楚valueForKey:和setValue:forKey:的搜索模式,然后用runtime来找出对应的方法。通过方法名来判断KVC里对应的key。
先说valueForKey:
先找get<Key>, <key>, is<Key>, or _<key>这些名字的get方法。(找不到的话会找对应的NSArray/NSSet,这些在我的其他文章里有介绍)。如果该类的accessInstanceVariablesDirectly方法retrun的是YES。那么还会搜索有没有 _<key>, _is<Key>, <key>, or is<Key>这种名字的变量。
setValue:forKey:
先找set<Key>: or _set<Key>这种set方法(这里是强行翻译的,苹果文档用的不是mutator method而是accessor,望有懂的大佬不吝赐教)如果该类的accessInstanceVariablesDirectly方法retrun的是YES。那么还会搜索有没有 _<key>, _is<Key>, <key>, or is<Key>这种名字的变量。
我们已经知道了方法对应的属性名。下面就是用runtime来找出都有哪些get方法和set方法。
这里用OC以get方法为例。(觉得没必要再写一个swift的,就是一个测试用的demo。)
- (NSArray *)getAllMethods:(Class)class
{
unsigned int methodCount = 0;
Method* methodList = class_copyMethodList(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 *returnType = method_copyReturnType(temp);
char retType[512] = {};
method_getReturnType(temp, retType, 512);
const char* encoding =method_getTypeEncoding(temp);
NSLog(@"方法名:%@,参数个数:%d,编码方式:%@,返回参数%s",[NSString stringWithUTF8String:name_s],
arguments,
[NSString stringWithUTF8String:encoding], retType);
if ([[NSString stringWithFormat:@"%s", retType] isEqualToString:@"@"]) {
//这里的@是来自@encode,表示返回值为对象.
[methodsArray addObject:[NSString stringWithUTF8String:name_s]];
}
}
free(methodList);
return methodsArray;
}
最后加个@encode表:
WechatIMG694.png
网友评论