I call a heartBeats
method per 10ms in a specific thread(not main thread), how to call another method at any time in this same thread?
I subclass NSThread
like this
@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
and run it like this
@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
Now,here is the question, how to run - (void)someMethod
in myThread
?
The main
method of your NSThread subclass is everything that runs on that thread. You cannot interrupt it to run other code without the main
method's cooperation.
What you really should do is throw out that entire loop and replace it with NSRunLoop and NSTimer.
You need your thread to do two things:
heartBeats
message (you're doing this)someMethod
message (this is what you asked about)For the latter, you need one additional thing: A run loop source.
So, clear out your main
method and replace it with the following:
self
and selector is heartBeats
. (Slightly cleaner version: Have another method that takes an NSTimer *but ignores it, so your timer calls that method and that method calls heartBeats
. The proper way to set up a timer is to give it a method that expects to be called with a timer, but, in practice, giving it a method that takes no arguments works, too.)scheduledTimerWith…
, add it to the run loop. (The scheduledTimerWith…
methods do this for you.)[myRunLoop run]
.Step 4 bears explaining:
Core Foundation (but not Foundation; I don't know why) has something called “run loop sources”, which are custom objects that can be added to a run loop and will call something once signaled.
Sounds like what you want, to call your view controller method!
First, in the view controller, change myThread
from a local variable in viewDidLoad
to an instance variable. Rename it _myThread
to make that clear.
Next, add a delegate
property to MyThread
. This should be weak
and have type id <MyThreadDelegate>
. You'll also need to define a MyThreadDelegate
protocol, which should have one method taking no arguments and returning nothing (void
).
You should now be able to set _myThread.delegate = self
from the view controller, and implement in the view controller the method that you declared in the protocol. The view controller is now the delegate of its MyThread.
In -[MyThread main]
, create a version-0 CFRunLoopSource. The Create function takes a “context” structure, containing, among other things, the version (0), an “info” pointer (set this to self
, i.e., the MyThread) and a Perform callback (a function, which will be called with the info
pointer as its only argument).
In your perform callback, you'll need to do something like this:
MyThread *self = (__bridge MyThread *)info;
[self fireDelegateMessage];
In MyThread, implement that fireDelegateMessage
method. In there, send self.delegate
the message you declared in your protocol.
Next, add a public method to MyThread (i.e., declare it in MyThread.h as well as implementing it in MyThread.m) named something like “requestDelegateMessage”. In this method, call CFRunLoopSourceSignal
on the run loop source. (The documentation for that function suggests that you also need to call CFRunLoopWakeUp
on the thread's CFRunLoop
. Try it without first.)
Lastly, when the view controller wants someMethod
to be called on that thread, call [_myThread requestDelegateMessage]
.
So:
requestDelegateMessage
requestDelegateMessage
signals the run loop source (and wakes up the run loop, if that is needed)fireDelegateMessage
on the MyThread's threadfireDelegateMessage
calls the view controller's implementation of the delegate method on the MyThread's threadsomeMethod
on the MyThread's thread