美文网首页
主线程相关、performSelector相关

主线程相关、performSelector相关

作者: 玉米须须 | 来源:发表于2019-01-12 22:38 被阅读0次

串行队列:
1、自己创建
2、主队列,特殊的串行队列(和主线程相关联),放在主队列中的任务,都会放到主线程中执行

主队列+异步函数
主队列优先,不会开启线程,所有的任务都在主线程中串行执行
串行队列+异步函数
不会开启子线程,所有的任务在当前线程中串行执行
并发队列+同步函数
不会开启子线程,所有的任务在当前线程中串行执行
并发队列+异步函数
会开启多条子线程,所有的任务并发执行
例如:

同步函数+主队列。会造成死锁

原因:主队列中有任务的时候,主队列就会安排主线程来执行该任务。但是在调度之前会检查主线程的状态,住过主线程在忙,就暂停调度。 知道主线程空闲为止。

dispatc_queue_t queue = dispathch_get_main_queue();//任务需要由主线程来执行,但是现在主线程在 执行第一个sync函数
NSlog(@"0");
dispatch_sync(queue,^{
    NSlog(@"1")';
}); 
dispatch_sync(queue,^{
    NSlog(@"2")';
}); 
dispatch_sync(queue,^{
    NSlog(@"3")';
}); 
dispatch_sync(queue,^{
    NSlog(@"4")';
}); 
dispatch_sync(queue,^{
    NSlog(@"5")';
}); 

注意:
如果以上整段代码放在子线程中执行,则不会造成死锁

异步函数+主队列,不会造成死锁

dispatc_queue_t queue = dispathch_get_main_queue();//任务需要由主线程来执行,但是现在主线程在 执行第一个sync函数
NSlog(@"0");
dispatch_async(queue,^{
    NSlog(@"1")';
}); 
dispatch_async(queue,^{
    NSlog(@"2")';
}); 
dispatch_async(queue,^{
    NSlog(@"3")';
}); 
dispatch_async(queue,^{
   NSlog(@"4")';
}); 
dispatch_async(queue,^{
   NSlog(@"5")';
}); 

原因:执行到1的时候,需要让主队列执行任务,但是主队列现在不空闲,又因为是异步函数,就会跳过1往下执行,而不会一直等待,同理跳过2、3、4、5,直到5个任务都添加到队列中,后面没有任务了,既然没有任务了,那就说明主线程终于空闲了。 现在就可以来执行这几个任务了。是把下边的任务全部过掉后,在回过头来之星这几个任务,然后依次取出任务执行,

perfomerSelecotr相关
- (void)viewDidLoad{
    NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadMethod) object:nil];
    [thread start];
}

- (void)threadMethod{
      [self performSelector:@selector(delayTest) withObject:nil afterDelay:0.1];  
}

- (void)delayTest{
     NSlog(@"This delayTest method");
}

如果在子线程中使用延时方法,delayTest是不会被执行的
原因:在子线程里调用延时函数,需要计时器,而子线程默认不自动创建runloop,导致没有计时器工作
解决方案:
1、在子线程里启动runloop

- (void)threadMethod{
      [self performSelector:@selector(delayTest) withObject:nil afterDelay:0.1];  
      //启动runloop
      [[NSrunloop currentRunloop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
      [[NSrunloop currentRunloop] run ];
}

2、调用GCD的延时函数

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self runTime2];
});
PerformSelector:afterDelay 相关
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSString *> *)modes;

区别在于第二个方法里指定了Runloop的mode,
#######注意:方法是异步的,只能在主线中执行

- (void)viewDidLoad {
    [super viewDidLoad];

    NSLog(@"before performdeleay");
    [self performSelector:@selector(deleayTest:) withObject:@"delaytest" afterDelay:0];
    sleep(6);
    NSLog(@"after performdeleay");
}

- (void)deleayTest:(NSString *)test {
    NSLog(@"doSomething:%@, currentThread = %@", test , [NSThread currentThread]);
}

打印结果是:

before performdeleay
(6s 后)
after performdeleay
doSomething:delaytest, currentThread = <NSThread: 0x7fdf73706c70>{number = 1, name = main}

可以看到,这个方法不会阻塞当前线程,而是把selector加入到主队列里,delay之后执行方法。即使delay时间为0,如果主线程在执行任务,那只能等到主线程执行完所有任务以后才会去执行selector。
那么delay的即时时间是从什么时候开始的呢,performSelector时候开始计算,就算主线程在阻塞也会计算时间,当主线程执行完以后,如果到了delay的时间,就会去执行selector,如果不到就继续deleay。

相关文章

网友评论

      本文标题:主线程相关、performSelector相关

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