RunLoop应用篇–线程间通信
本文将承接上一章节,讲解关于RunLoop的应用问题,本文主要介绍线程通信的相关问题,说到线程通信,其实主要有两种方式:
1.performSelect On The Thread
2.Mach Port
performSelect On The Thread
框架为我们提供了强制在某个线程中执行方法的途径,如果两个非主线程的线程需要相互间通信,可以先将自己的当前线程对象注册到某个全局的对象中去,这样相互之间就可以获取对方的线程对象,然后就可以使用下面的方法进行线程间的通信了,由于主线程比较特殊,所以框架直接提供了在主线程执行的方法。
下面是提供的一些方法:
@interface NSObject (NSThreadPerformAdditions)
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);
@end
其实,平常我们也会经常使用到这些方法,实际上就是线程之间的通信。
Mach Port
在苹果的Thread Programming Guide的Run Pool一节的Configuring a Port-Based Input Source 这一段中就有使用Mach Port进行线程间通信的例子。 其实质就是父线程创建一个NSMachPort对象,在创建子线程的时候以参数的方式将其传递给子线程,这样子线程中就可以向这个传过来的 NSMachPort对象发送消息,如果想让父线程也可以向子线程发消息的话,那么子线程可以先向父线程发个特殊的消息,传过来的是自己创建的另一个 NSMachPort对象,这样父线程便持有了子线程创建的port对象了,可以向这个子线程的port对象发送消息了。
当然各自的port对象需要设置delegate以及schdule到自己所在线程的RunLoop中,这样来了消息之后,处理port消息的delegate方法会被调用,你就可以自己处理消息了。
自己也尝试去实现主线程和子线程之间的通信,没有按照官方文档的实现方式,大致实现如下:
1.RunLoop add port
#pragma mark - add port
- (void)addPort
{
if (self.port)
{
// This class handles incoming port messages.
[self.port setDelegate:self];
// Install the port as an input source on the current run loop.
[[NSRunLoop currentRunLoop] addPort:self.port forMode:NSRunLoopCommonModes];
}
}
首先,需要给主线程的runloop添加port,然后实现delegate。
2.开启子线程
#pragma mark - launchSecondThread
- (void)launchSecondThread{
__weak AppDelegate *weakSelf = self;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// Create the check-in message.
NSPortMessage* messageObj = [[NSPortMessage alloc] initWithSendPort:weakSelf.port receivePort:weakSelf.port components:nil];
if (messageObj)
{
// Finish configuring the message and send it immediately.
[messageObj setMsgid:8];
[messageObj sendBeforeDate:[NSDate date]];
}
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// Create the check-in message.
NSPortMessage* messageObj = [[NSPortMessage alloc] initWithSendPort:weakSelf.port receivePort:weakSelf.port components:nil];
if (messageObj)
{
// Finish configuring the message and send it immediately.
[messageObj setMsgid:10];
[messageObj sendBeforeDate:[NSDate date]];
}
});
}
此处,开启了两个子线程,主要使用NSPortMessage像同一个port发送消息,然后在port的delegate中处理消息,这里只是简单接受了线程的通信。
NSPortMessage好像只能在OS X上面使用,iOS平台上面不可用,代码示例也是在Mac平台上实现的。
这里,并没有完全按照官方文档的方式,感觉官方的文档更像是object之间的通信,具体可以参考官网的介绍。
总结
文中主要介绍了使用port进行线程之间的通信,介绍的比较简单,自己也写了一个demo,大家可以去我的github上查看。