我在特定线程(非主线程)中每10ms调用一个heartBeats
方法,如何在同一个线程中随时调用另一个方法?
我像这样<{p>}子类NSThread
@implementation MyThread
{
NSTimeInterval _lastTimeInterval;
}
- (void)main
{
while (true) {
NSTimeInterval timeInterval = [[NSDate date] timeIntervalSince1970]*1000;
if (timeInterval - _lastTimeInterval > 10)
{
[self heartBeats];
_lastTimeInterval = timeInterval;
}
}
}
- (void)heartBeats
{
NSLog(@"heart beats thread: %@", [NSThread currentThread].description);
}
@end
并像这样运行
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"main thread: %@", [NSThread currentThread].description);
MyThread *myThread = [[MyThread alloc]init];
[myThread start];
}
- (void)someMethod
{
// do somthing
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
现在,问题是如何在- (void)someMethod
中运行myThread
?
答案 0 :(得分:4)
NSThread子类的main
方法是在该线程上运行的所有内容。如果没有main
方法的合作,你不能打断它来运行其他代码。
你真正要做的就是抛弃整个循环并用NSRunLoop和NSTimer替换它。
你需要你的线程做两件事:
heartBeats
消息(您正在执行此操作)someMethod
消息(这是您询问的内容)对于后者,你需要另外一件事:一个运行循环源。
因此,请清除您的main
方法并将其替换为以下内容:
self
,选择器为heartBeats
。 (稍微更干净的版本:有另一种方法,它接受NSTimer *但忽略它,所以你的计时器调用该方法,该方法调用heartBeats
。正确的方式设置一个计时器是给它一个期望用计时器调用的方法,但实际上,给它一个不带参数的方法也可以。)scheduledTimerWith…
创建计时器,请将其添加到运行循环中。 (scheduledTimerWith…
方法为您执行此操作。)[myRunLoop run]
。第4步可以解释:
核心基金会(但不是基金会;我不知道为什么)有一个叫做“运行循环源”的东西,它是可以添加到运行循环中的自定义对象,一旦发出信号就会调用它。听起来像你想要的,调用你的视图控制器方法!
首先,在视图控制器中,将myThread
中的viewDidLoad
中的局部变量更改为实例变量。将其重命名_myThread
以使其清晰。
接下来,将delegate
属性添加到MyThread
。这应该是weak
并且类型为id <MyThreadDelegate>
。您还需要定义一个MyThreadDelegate
协议,该协议应该有一个方法不带参数并且不返回任何内容(void
)。
您现在应该能够从视图控制器设置_myThread.delegate = self
,并在视图控制器中实现您在协议中声明的方法。视图控制器现在是其MyThread的委托。
在-[MyThread main]
中,创建一个版本0 CFRunLoopSource。 Create函数采用“上下文”结构,其中包含版本(0),“info”指针(将其设置为self
,即MyThread)和Perform回调(函数,将使用info
指针作为唯一参数调用。
在演出回调中,您需要执行以下操作:
MyThread *self = (__bridge MyThread *)info;
[self fireDelegateMessage];
在MyThread中,实现fireDelegateMessage
方法。在那里,发送self.delegate
您在协议中声明的消息。
接下来,将一个公共方法添加到MyThread(即,在MyThread.h中声明它以及在MyThread.m中实现它),其名称类似于“requestDelegateMessage”。在此方法中,在运行循环源上调用CFRunLoopSourceSignal
。 (该功能的文档表明您还需要在主题CFRunLoopWakeUp
上致电CFRunLoop
。请先试用。)
最后,当视图控制器希望在该线程上调用someMethod
时,请调用[_myThread requestDelegateMessage]
。
所以:
requestDelegateMessage
requestDelegateMessage
表示运行循环源(并唤醒运行循环,如果需要)fireDelegateMessage
fireDelegateMessage
调用视图控制器在MyThread线程上执行委托方法someMethod