什么是线程通信,线程间如何通信,有哪些常见的线程通信方式?可能我们经常听到这个问题,下面关于这个问题,我们来详细的总结一下(收集整理一下网上各位大佬的博客汇总)。

一、问题的理解

  1. 一个线程传递数据给另一个线程。
  2. 在一个线程中执行完特定的任务之后,转到另一个线程继续执行任务。

二、NSObject对象的线程通信方式

1. 在主线程添加执行方法

withObject id类型的参数可以传递给调用的方法 waitUntilDone设置YES ,代表等待当前线程执行完毕。

[self performSelectorOnMainThread:@selector(doSomething:) withObject:@[@"添加到主线程"] waitUntilDone:YES];

2. 把需要执行的操作放到后台线程

[self performSelectorInBackground:@selector(doSomething:) withObject:@[@"后台线程"]];

三、GCD通信方式

1. 回归主线程

很多时候在子线程处理完数据需要回到主线程更新UI的时候,可以调用如下方法。

dispatch_async(dispatch_get_main_queue(), ^{
   // doSomething
});

2. 全局队列

dispatch_get_global_queue(long identifier, unsigned long flags) 函数有两个参数,第一个identifier设置全局队列优先级,有四个优先级,分别是

DISPATCH_QUEUE_PRIORITY_HIGH 全局队列 高优先级

DISPATCH_QUEUE_PRIORITY_DEFAULT 全局队列 默认优先级

DISPATCH_QUEUE_PRIORITY_LOW 全局队列 低优先级

DISPATCH_QUEUE_PRIORITY_BACKGROUND 全局队列 后台优先级

第二个参数是保留参数,指定为0,在开发中遇到一些大批量数据处理查询等操作可以使用如下方法。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // doSomething
});

3. 同步操作

一般用于在开发中处理一些单线程同步的操作。

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // doSomething
});

四、 NSThread通信方式

1. 自定义线程

自定义线程,将当前数据转移到指定的线程去操作,但是这种方法经常会遇到线程退出造成崩溃,不建议使用。

NSThread *thread = [[NSThread alloc] init];
[thread start];
[self performSelector:@selector(doSomething:) onThread:thread withObject:@[@"自创线程"] waitUntilDone:YES];

下面这种方法可以避免线程退出情况

NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(dothing:) object:@[@"自创线程2"]];
[thread2 start];

还有一种方法可以直接把响应的操作放到子线程,这种方法会立即在子线程执行响应的方法,与performSelectorInBackground:方法等价。

[NSThread detachNewThreadSelector:@selector(backGroundMethod) toTarget:self withObject:@[@"自创线程3"]];

当然,我们也可以增加一个特殊的线程常驻RunLoop,防止线程退出

NSThread *runLoopThread = [[NSThread alloc] initWithTarget:self selector:@selector(onRunLoop) object:nil];
[runLoopThread start];
[self performSelector:@selector(dothingOnRunLoop:) onThread:runLoopThread withObject:@[@"常驻RunLoop线程"] waitUntilDone:YES];

// 常驻runLoop
- (void)onRunLoop {
    @autoreleasepool {
        [NSThread currentThread].name = @"常驻RunLoop线程";
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

// 在runloop上执行操作
- (void)dothingOnRunLoop:(id)param {
    // 可以在此打断点测试线程是否已经加入runloop
    NSLog(@"跑在runloop上的线程: %@", param);
}

五、NSOperationQueue通信方式

还有NSOperationQueue也可以用于线程通信,不过使用的时候不多,比如在主队列增加执行操作

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    NSLog(@"在主队列增加执行Block");
}];

六、总结

以上就是iOS中常用的几种通信方式,在项目中可以根据需求灵活使用。