故事的发生还要说到一个小功能:让UISearchBar的placeholder文字居左显示,就看到了上的一篇:http://www.jianshu.com/p/86410191b4b2 思路介绍的很好。最核心的东西也就是
RunTime
中NSInvocation
改写系统自带方法。
现在我们倒推我们的思考过程
1,知其然<不知>其所以然
1.我们查找到了一个系统方法,然后替换系统方法,一个分类扩展一个方法就搞定
-(void)changeLeftPlaceholder:(NSString *)placeholder {
self.placeholder = placeholder;
SEL centerSelector = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"setCenter", @"Placeholder:"]);
if ([self respondsToSelector:centerSelector]) {
BOOL centeredPlaceholder = NO;
NSMethodSignature *signature = [[UISearchBar class] instanceMethodSignatureForSelector:centerSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:self];
[invocation setSelector:centerSelector];
[invocation setArgument:¢eredPlaceholder atIndex:2];
[invocation invoke];
}
}
2.我们Runtime
打印系统方法查找到了一个设置placeholder
居中的一个方法
NSString *name = NSStringFromSelector(selector);
const char *type = method_getTypeEncoding(method);
NSLog(@"调用方法: %@ Type: %s",name,type);
打印很多,找到一个相关结果:
调用方法: setCenterPlaceholder: Type: v20@0:8B16
3,我们试着去理解这个方法
setCenterPlaceholder:
字面上理解这个方法是设置placeholder
文字居中的方法,后面:跟了一个参数。好吧,我们需要知道这个参数的类型,这样才能确定这个方法是否可以被修改。
Runtime中method_getTypeEncoding()
我们可以打印setCenterPlaceholder:
的参数类型
/**
* Returns a string describing a method's parameter and return types.
*
* @param m The method to inspect.
*
* @return A C string. The string may be \c NULL.
*/
OBJC_EXPORT const char *method_getTypeEncoding(Method m)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
我们的打印结果是:Type: v20@0:8B16
这都到了今天我要说的重点types
类型编码
2,知其然<知>其所以然
types
在官方文档上的解释:
An array of characters that describe the types of the arguments to the method. For possible values,Since the function must take at least two arguments—self and _cmd, the second and third characters must be “@:” (the first character is the return type).
可见他是一个characters 字符集合,表示一个方法或属性的字符编码,一般对于OCRuntime中,其至少有两个字符:@:
,其中第二个@
代表self
,方法的调用者,第三个:
代表方法的_cmd
指针,第一个值是返回类型。
说到这里再来看看我们这个方法setCenterPlaceholder:
的类型编码:v20@0:8B16
,这里我们先不看数字(下面会讲数字的含义)为v@:B
,我们看一下,这第二个字符@
,第三个字符:
是不是就刚好印证了官方文档上的说的,那么问题来了第一个v
代表什么了,答案就在这个表里
通过这个表你会发现,v
代表void
,就是无返回值空类型,那么最后的B
就代表C或C++的bool
类型了。好了,到这里我们就可以解释一下方法setCenterPlaceholder:
的参数类型了:
这个方法传入了一个布尔值,返回结果是void
好了,我们根据字面意思和传入的参数类型判断这个方法可以设置'placeholder'文字是否居中了。
那么那些数字又代表什么?
我们在UISearchBar
的分类里面来一个方法:
-(void)printAllSEL{
unsigned int count;
Method *methods = class_copyMethodList([self class], &count);
for (int i = 0; i < count; i++){
Method method = methods[i];
SEL selector = method_getName(method);
NSString *name = NSStringFromSelector(selector);
const char *type = method_getTypeEncoding(method);
NSLog(@"调用方法: %@ Type: %s",name,type);
}
}
打印结果部分如下:
调用方法: _animatedAppearanceBarButtonItem Type: @16@0:8
调用方法: _setBackgroundLayoutNeedsUpdate: Type: v20@0:8B16
调用方法: _setBackdropStyle: Type: v24@0:8Q16
调用方法: _backdropStyle Type: Q16@0:8
调用方法: setCenterPlaceholder: Type: v20@0:8B16
调用方法: _hasDarkUIAppearance Type: B16@0:8
调用方法: searchFieldLeftViewMode Type: q16@0:8
调用方法: setSearchFieldLeftViewMode: Type: v24@0:8q16
调用方法: _alternateTitle Type: @16@0:8
调用方法: _setCancelButtonWantsLetterpress Type: v16@0:8
总结一下规律,你会发现所有的第二个@
后面都是0
,第三个:
都是8,好的,可能是一些偏移量之类的,文档没介绍,也不知道啥意思?不过可以参考这个小文章,https://code.google.com/archive/p/jscocoa/wikis/MethodEncoding.wiki
欢迎知道的同学留言告知,相互学习,谢谢!
碰到一个问题,我们还是应该多思考,还是孔夫子说的好:学而不思则罔,思而不学则殆