问题
I'm not sure how to use the API performSelector:onThread
and I need some suggestions here.
As far as I known, I need a runloop
to make the call of performSelector:onThread
, so I made one. But then I find a problem : once I called performSelector:onThread
, the runloop
stops.
Here 's my test code, runloop is in function kickOffThread
.
- (void)setCurrentThread
{
self.thread = [NSThread currentThread];
}
- (void)kickOffThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self performSelector:@selector(setCurrentThread) withObject:nil afterDelay:0];
while (!threadCheck) {
NSLog(@"threadCheck = %d", threadCheck);
[[NSRunLoop currentRunLoop] run];
}
[self doSomeCleanUp];
NSLog(@"thread exit ....");
[pool release];
}
I call kickOffThread
by performInBackground
:
[self performSelectorInBackground:@selector(kickOffThread) withObject:nil];
In mainThread I call following API to set threadCheck to be YES, it is correctly called, but my thread loop suddenly stops.
[self performSelector:@selector(signalThreadCheck) onThread:self.thread withObject:nil waitUntilDone:NO];
-(void)signalThreadCheck
{
NSLog(@" signalThreadCheck ... ");
threadCheck = YES;
}
terminal log result is as follows, "thread exit ...." not printed. Anyone tells me where is the problem ?
2013-06-07 15:51:54.827 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.827 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.827 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.836 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.840 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.844 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.846 MBSMapSample[23582:17403] signalThreadCheck ...
回答1:
the thread is not breaked. it just stucked in mach_msg_trap
If no input sources or timers are attached to the run loop, this method exits immediately; otherwise, it runs the receiver in the NSDefaultRunLoopMode
the perfromSelector:onThread cause the caller add a input source to the target thread. so the method [NSRunLoop run] will actually call [NSRunLoop(NSRunLoop) runMode:beforeDate:] and send a infinite date as beforeDate param.
if you want to stop the thread, use [NSRunLoop(NSRunLoop) runMode:beforeDate:] instead, and send a limited date, like this:
BOOL shouldKeepRunning = YES; // global
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning &&
[theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
回答2:
It would help to know exactly what you're trying to accomplish here, because the meta-question is whether NSThread
is the right tool for the task. GCD is often preferred.
Nonetheless, one of the things to consider is whether the NSRunLoop
has an input source or not. Let's take a slightly simplified case where we detach a new NSThread
as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
_threadCheck = NO; // this is an ivar
[NSThread detachNewThreadSelector:@selector(kickOffThread) toTarget:self withObject:nil];
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
for( uint8_t i = 0; i < 10; i++ )
[self performSelector:@selector(logSomething) onThread:self.thread withObject:nil waitUntilDone:NO];
[self performSelector:@selector(signalThreadCheck) onThread:self.thread withObject:nil waitUntilDone:NO];
});
}
- (void)kickOffThread
{
_thread = [NSThread currentThread]; // this is an ivar
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
while( !_threadCheck && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] );
[self doSomeCleanUp];
printf("thread exit...\n");
}
- (void)doSomeCleanUp {
printf("cleaning up...\n");
}
- (void)logSomething {
printf("in background thread...\n");
}
-(void)signalThreadCheck
{
printf("signalThreadCheck\n");
_threadCheck = YES;
}
On the console, I get:
cleaning up...
thread exit...
Why was logSomething
never called? Because the run loop for the background thread that we spawned has no input source, so it exits immediately. If we add an input source with [NSPort port]
for example, we can keep the spawned thread's run loop turning, e.g.:
- (void)kickOffThread
{
_thread = [NSThread currentThread];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSPort port] forMode:NSRunLoopCommonModes];
while( !_threadCheck && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] );
[self doSomeCleanUp];
printf("thread exit...\n");
}
Now we print the following to the console:
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
signalThreadCheck
cleaning up...
thread exit...
More about run loops and from the documentation:
If no input sources or timers are attached to the run loop, this method [run] exits immediately; otherwise, it runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking runMode:beforeDate:. In other words, this method effectively begins an infinite loop that processes data from the run loop’s input sources and timers.
来源:https://stackoverflow.com/questions/16979020/performselectoronthread-breaks-runloop