iOS performSelector(参考)

在项目中,常常用到performSelector之类的方法,而且有很多类似方法;今天就来召集一下!
第一点 performSelector的使用

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
 
    /*performSelector
     - (id)performSelector:(SEL)aSelector;
     - (id)performSelector:(SEL)aSelector withObject:(id)object;
     - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
     
      - (BOOL)respondsToSelector:(SEL)aSelector;
     */
    
    //其次,进行调用
    //没有参数
    BOOL isNoParam= [self respondsToSelector:@selector(methodNoParam)];
    if (isNoParam) {
        [self performSelector:@selector(methodNoParam)];
    }
    
    //一个参数
    BOOL isOneParam= [self respondsToSelector:@selector(methodWithOneParam:)];
    if (isOneParam) {
        [self performSelector:@selector(methodWithOneParam:) withObject:@"first"];
    }
    
    //二个参数
    BOOL isParams= [self respondsToSelector:@selector(methodWithParams: andParamSecond:)];
    if (isParams) {
        [self performSelector:@selector(methodWithParams: andParamSecond:) withObject:@"first" withObject:@"second"];
    }

    //建立动态的函数,然后调用它们
    NSArray *objectArray = @[@{@"methodName":@"DynamicParameterString:", @"value":@"String"},
                           @{@"methodName":@"DynamicParameterNumber:", @"value":@2}];
    for (NSDictionary *dic in objectArray) {
        SEL selector = NSSelectorFromString([dic objectForKey:@"methodName"]);
        if ([self respondsToSelector:selector]) {
            //这里会有警告:PerformSelector may cause a leak because its selector is unknown
            [self performSelector:selector withObject:[dic objectForKey:@"value"]];
        }
    }
    
    //PerformSelector may cause a leak because its selector is unknown 解决方法
    //1.使用函数指针方式
    for (NSDictionary *dic in objectArray) {
        SEL selector = NSSelectorFromString([dic objectForKey:@"methodName"]);
        if ([self respondsToSelector:selector]){
            IMP imp = [self methodForSelector:selector];
            void (*func)(id, SEL) = (void *)imp;
            func(self, selector);
        }
    }
    //其它方法消除警告:http://www.tuicool.com/articles/iu6zuu

}

//首先,定义要调用的方法
- (void)methodNoParam{
    NSLog(@"methodNoParam");
}

- (void)methodWithOneParam:(id)paramFirst{
    NSLog(@"methodWithOneParam: %@", paramFirst);
}

- (void)methodWithParams:(id)paramFirst andParamSecond:(id) paramSecond{
    NSLog(@"methodWithOneParam: %@,%@", paramFirst,paramSecond);
}


- (void)DynamicParameterString:(NSString *)string{
    NSLog(@"DynamicParameterString: %@",string);
}

- (void)DynamicParameterNumber:(NSNumber *)number{
    NSLog(@"DynamicParameterNumber: %@",number);
}

这里需要补充的知识:关于performSelector调用和直接调用方法的区别
1、performSelector是运行时系统负责去找方法的,在编译时候不做任何校验;如果直接调用编译是会自动校验。
如果methodNoParam、methodWithOneParam:、methodWithParams: andParamSecond:不存在
那么直接调用:在编译时候就能够发现(借助Xcode可以写完就发现),但是使用performSelector的话一定是在运行时候才能发现(此时程序崩溃);
Cocoa支持在运行时向某个类添加方法,即方法编译时不存在,但是运行时候存在,这时候必然需要使用performSelector去调用。
所以有时候如果使用了performSelector,为了程序的健壮性,会使用检查方法respondsToSelector。
2、直接调用方法时候,一定要在头文件中声明该方法的使用,也要将头文件import进来。而使用performSelector时候, 可以不用import头文件包含方法的对象,直接用performSelector调用即可。

3、performSelector是在iOS中的一种方法调用方式。他可以向一个对象传递任何消息,而不需要在编译的时候声明这些方法。所以这也是runtime的一种应用方式。
所以performSelector和直接调用方法的区别就在与runtime。直接调用编译是会自动校验。如果方法不存在,那么直接调用 在编译时候就能够发现,编译器会直接报错。
但是使用performSelector的话一定是在运行时候才能发现,如果此方法不存在就会崩溃。所以如果使用performSelector的话他就会有个最佳伴侣respondsToSelector:;来在运行时判断对象是否响应此方法。
备注:runtime???
在这小作总结:OC是运行时语言,只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法。利用runtime机制让我们可以在程序运行时动态修改类、对象中的所有属性、方法,就算是私有方法以及私有属性都是可以动态修改的。

// 动态添加方法
// 开发场景:如果一个类方法非常多,加载了到内存的时候也比较耗费资源,需给每个方法生成映射表,可以使用动态给某个类,添加方法解决.
// 经典面试题:有没有使用preformSelector,其实主要想问有没有添加过方法;

performSelector相关的应用:传递三个及以上的参数
第一种:NSInvocation
第二种:把多个参数封装成一个参数
在这里不做描述:详情参考 https://my.oschina.net/ososchina/blog/644117
第三种:objc_msgSend

NSString *str = @"字符串objc_msgSend";
NSNumber *num = @20;
NSArray *arr = @[@"数组值1", @"数组值2"];
SEL sel = NSSelectorFromString(@"ObjcMsgSendWithString:withNum:withArray:");

((void (*) (id, SEL, NSString *, NSNumber *, NSArray *)) objc_msgSend) (self, sel, str, num, arr);

- (void)ObjcMsgSendWithString:(NSString *)string withNum:(NSNumber *)number withArray:(NSArray *)array {
    NSLog(@"%@, %@, %@", string, number, array[0]);
}

参数中有结构体的处理方式

typedef struct ParameterStruct{
    int a;
    int b;
}MyStruct;

NSString *str = @"字符串 把结构体转换为对象";
NSNumber *num = @20;
NSArray *arr = @[@"数组值1", @"数组值2"];

MyStruct mystruct = {10,20};
NSValue *value = [NSValue valueWithBytes:&mystruct objCType:@encode(MyStruct)];

SEL sel = NSSelectorFromString(@"NSInvocationWithString:withNum:withArray:withValue:");
NSArray *objs = [NSArray arrayWithObjects:str, num, arr, value,nil];

[self performSelector:sel withObjects:objs];

- (void)NSInvocationWithString:(NSString *)string withNum:(NSNumber *)number withArray:(NSArray *)array withValue:(NSValue *)value{

    MyStruct struceBack;
    [value getValue:&struceBack];

    NSLog(@"%@, %@, %@, %d", string, number, array[0],struceBack.a);
}

第二点

/**
 在主线程上执行指定的方法,使用默认的模式(NSDefaultRunLoopMode)
 默认的模式指:主线程中的方法进行排队,是一个循环队列,并且循环执行。
这个函数表示在主线程上执行方法,YES表示需要阻塞主线程,直到主线程将我们的代码块执行完毕。

 @param aSelector 要在主线程执行的方法,该方法不能有返回值,并且只能有一个参数。
 @param arg 要传递的参数,如果无参数,就设为nil。
 @param wait 要执行的aSelector方法,是否马上执行。
 如果设置为YES:等待当前线程执行完以后,主线程才会执行aSelector方法;
 设置为NO:不等待当前线程执行完,就在主线程上执行aSelector方法。
 如果,当前线程就是主线程,那么aSelector方法会马上执行。
 
 该方法用途:因为iPhone编程,对UI的修改,只能在主线程上执行。可以用该方法来完成UI的修改。
 */
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait {
       NSLog(@"用的多");
}

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array {

}

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait {
    
}

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array {

}

/**
 在当前线程中执行指定的方法,使用默认模式,并指定延迟。

 @param aSelector 指定的方法。含义同上,不在赘述。
 @param anArgument 同上
 @param delay 指定延迟时间(秒)。
 */
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay {
      NSLog(@"用的多");
}

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes {

}

这里需要补充的知识:
Runloop 相当于 win32 里面的消息循环机制,它可以让你根据事件/消息(鼠标消息,键盘消息,触摸事件,计时器消息等)来调度线程。
比如:在触摸 UIView 时之所以能够激发 touchesBegan/touchesMoved 等等函数被调用。系统会自动为应用程序的主线程生成一个与之对应的 run loop 来处理其消息循环。让调用更加简单。也避免了繁琐,复杂的操作。
一句话:Runloop是一种消息处理机制!

参考链接:
http://www.jianshu.com/p/672c0d4f435a
http://blog.sina.com.cn/s/blog_7b9d64af0101bjw4.html
http://blog.csdn.net/meegomeego/article/details/20041887

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,036评论 29 470
  • 目录 Objective-C Runtime到底是什么 Objective-C的元素认知 Runtime详解 应用...
    Ryan___阅读 1,896评论 1 3
  • 平均3个通宵读完来形容这本书的,其实不然,而我花了三个半天和晚上看完的,故事的每个章节穿插着好几个国家,因为这次长...
    严素阅读 481评论 0 0
  • 当人生还剩下一百个小时,你就会死亡,你会做什么? 很多人面对死亡,更多的是对未知的恐惧,所有活在世界上的人都不知道...
    银花浩天阅读 213评论 0 0
  • 今天是2017年2月26日,我读完了计划中的第一本书,由王臣写的《今生就这样开始 三毛传》,我的读书感受如下: 读...
    小米粥毛毛阅读 941评论 0 1