美文网首页
iOS performSelector && afterDela

iOS performSelector && afterDela

作者: Rockerliang | 来源:发表于2020-04-18 16:04 被阅读0次

首先来段代码

 - (void)viewDidLoad {
    [super viewDidLoad];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self performSelector:@selector(test:) withObject:@"aaa"];
        [self performSelector:@selector(test:) withObject:@"bbb" afterDelay:3];
    });
}

- (void)test:(NSString *)object
{
    NSLog(@"======>:%@",object);
}

上面代码会输出什么呢?来跑一下看看:

======>:aaa

只会输出aaa,说明 [self performSelector:@selector(test:) withObject:@"bbb" afterDelay:3];并没有在延迟3s后执行test方法。下面看下为什么会这样。

performSelector && performSelector:withObject:afterDelay:区别

  • performSelector
    我们看下performSelector的定义:

    截屏2020-04-18下午3.26.07.png
    看到performSelector方法是在NSObject类中定义的,接下来再看看加上afterDelay的performSelector方法定义
  • performSelector:withObject:afterDelay:


    截屏2020-04-18下午3.27.09.png

    可以看到是在NSRunloop中定义的,下面说一下具体的区别

  • 区别:
    1.performSelector
    实际是为了方便使用objc_msgSend 的一个简单的封装,等同于:

((void (*) (id, SEL, NSString *)) objc_msgSend)(self, NSSelectorFromString(@"test:"), @"aaa");

performSelector默认最多只可传递两个参数,若需多参参考以下方式:
一种是使用NSInvocation,利用了runtime的反射机制,效率较低,可读性不高;
第二种是将参数封装进NSArray、NSDictionary等对象,可读性强,效率高;
第三种是使用objc_msgSend重写performSelector。

而且他的方法执行所在的线程跟调用他的时候所在的线程是一致的

  1. performSelector:withObject:afterDelay:

拿上面的代码

 [self performSelector:@selector(test:) withObject:@"bbb" afterDelay:3];

该方法将延迟3秒后再执行test方法。说到对时间方面的处理在项目中经常用到的是NSTimer:当一个NSTimer注册到Runloop后,Runloop会重复的在相应的时间点注册事件,当然Runloop为了节省资源并不会在准确的时间点触发事件。
performSelector:withObject:afterDelay:其实就是在内部创建了一个NSTimer,然后会添加到当前线程的Runloop中,所以当该方法添加到子线程中的时候需要注意一点:子线程中的runloop默认是没有启动的状态。所以我们要让当前子线程的runloop跑起来:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [[NSRunLoop currentRunLoop] run];
        [self performSelector:@selector(test:) withObject:@"bbb" afterDelay:3];
    });

运行一下发现并没有任何作用,是因为run方法只是尝试想要开启当前线程中的runloop,但是如果该线程中并没有任何事件(source、timer、observer)的话,并不会成功的开启。
所以代码要改一下:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self performSelector:@selector(test:) withObject:@"bbb" afterDelay:3];
        [[NSRunLoop currentRunLoop] run];
    });

打印一下,会发现3s后会正常输出:======>:bbb
需要注意的是:
对于该performSelector延迟方法而言,如果在主线程中调用,那么test方法也是在主线程中执行;如果是在子线程中调用,那么test也会在该子线程中执行。


  • 结论:
    1.performSelector:withObject:只是一个单纯的消息发送,就是对 objc_msgSend的封装,和时间没有一点关系,所以不需要添加到子线程的Runloop中也能执行。
    2.performSelector:withObject:afterDelay:是在内部创建了一个NSTimer,然后会添加到当前线程的Runloop中,如果添加在子线程,由于子线程中的runloop默认是没有启动的状态,所以我们需要把子线程的Runloop跑起来才可。而且还要注意调用的顺序,必须先把timer (performSelector:withObject:afterDelay:)注册到runloop中,才可。

相关文章

网友评论

      本文标题:iOS performSelector && afterDela

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