美文网首页iOS开发攻城狮的集散地iOS直播视频iOS即时通讯
iOS 不走寻常路:调用方法的6种姿势,你知道几种

iOS 不走寻常路:调用方法的6种姿势,你知道几种

作者: Allan_野草 | 来源:发表于2018-06-19 09:30 被阅读29次

片头

某互联网公司。某天,项目代码已经写完,闲得心里发慌的老司机和小鲜肉两个人。
司机B:这位同学,来写下你平时是怎么样调用方法的,比如有个方法-hi。
鲜肉A:很简单啊,[target hi];你一个iOS连OC语法都不会吗,呵呵。
B:too weak,平时能不能提升下自己逼格please?和你说话都感觉自己low了很多耶
A:mdzz,这还能怎么写,不给你写bug就找茬是吗。。。
B:这你就不懂了吧,现在让你见识下我的操作!

正片

一、

调用方法还是有各种姿势的。
比如,target类的方法

-(void)hi
{
  NSLog(@"hello world!");
}

最简单的,调用[target hi],简单而粗暴。

二、

假如-hi没有在头文件中公开,是个私有方法呢?
没关系,OC的世界是流氓的世界,私有不存在的。就算私有也调给你看:

[target performSelector:@selctor(hi)];

同理,即使方法在私有库也是可以调用它的。

三、

有些时候performSelector,编译器会报警,因为在写代码的那个类文件找不到-hi方法。报warning啊,这可不行,与优雅的我格格不入。
于是有:

// objc_msgSend:向target发送hi消息。<objc/message>库的函数
((void(*)(id,SEL))objc_msgSend)(target,NSSelectorFromString(@"hi"));

objc_msgSend:什么上warning?
(备注:objc_msgSend要根据实际,进行强制类型转换。不然会报错)

四、

如果还是认为不够底层(逼格),Runtime表示加入战斗

// method_getImplementation:获取hi方法的IMP指针,并调用。<objc/runtime>库的函数
((void(*)(id,SEL))method_getImplementation(class_getInstanceMethod(target, @selctor(hi))))(target, @selctor(hi));

method_getImplementation:高冷。
(备注:method_getImplementation获取方法的IMP指针后调用,同样像objc_msgSend一样,要求强制类型转换)

五、

假如-hi是私有方法,并且有参数。比如两个参数,用performSelector也是可以的

-(void)hiWithObj1:(NSString *)obj1 obj2:(int)obj2
{
  NSLog(@"hello,%@,%d", obj1, obj2);
}
[target performSelector:@selector(hiWithObj1:obj2:) withObject:obj1 withObject:obj2];

但是
参数有三个呢?performSelector就不行了,不支持三个参数以上
取而代之是,使用objc_msgSend或者method_getImplementation是可行的。假设第三个参数是Block类型

// typedef void(^Block)(id);
((void(*)(id,SEL,NSString *,int,Block))objc_msgSend)(target,@selctor(hiWithObj1:obj2:obj3:),obj1,obj2,obj3);
六、NSInvocation

大OC作为面向对象语言,走在黑科技的前沿,怎么少得了封装呢。于是“调用方法”类,这样优秀的类就接着诞生了:

NSString *obj1 = @"参数一";
int obj2 = 2;
Block obj3 = ^(id o){NSLog(@"参数三");};

NSInvocation *caller = [NSInvocation invocationWithMethodSignature:[[target class] instanceMethodSignatureForSelector:@selector(hiWithObj1:obj2:obj3:)]];
caller.target = target;
caller.selector = @selector(hiWithObj1:obj2:obj3:);
[caller setArgument:&obj1 atIndex:2];
[caller setArgument:&obj2 atIndex:3];
[caller setArgument:&obj3 atIndex:4];
[caller invoke];

(备注:上面的index是从2开始的,因为默认index=0是id self,index=1是SEL _cmd)

片尾

司机B:所以说,条条大路通秋名山,6种你都get到了没?
鲜肉A:现在这些东西都是我的了。Copy粘贴才是真正的精粹
路过的X总:整天摸鱼,你们倒是给我做成PPT,好让我去忽悠不懂技术的客户啊,呵呵。

以上就是6种调用,特别是对于私有库私有方法的调用方式。平常你用过哪种实用的调用方法的呢?

End

相关文章

网友评论

    本文标题:iOS 不走寻常路:调用方法的6种姿势,你知道几种

    本文链接:https://www.haomeiwen.com/subject/uvbpsftx.html