Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use [performSelector: onThread: withObject: waitUntilDone:]?

I tried to subclass NSThread in order to operate a thread with some data. I want to simulate the join() in python, according to the doc:

join(): Wait until the thread terminates. This blocks the calling thread until the thread whose join() method is called terminates

So I think using performSelector: onThread: withObject: waitUntilDone:YES would be fine, but it does not work. It just do nothing and would not exit, running like forever.

This is my code:

@interface MyClass : NSThread
@property (strong, nonatomic) NSMutableArray *msgQueue;
@property (assign, nonatomic) BOOL stop;
@end

@implementation MyClass

-(id)init
{
    self = [super init];
    if (self) {
        self.msgQueue = [NSMutableArray array];
        self.stop = NO;
        [self start];
        return self;
    }
    return nil;
}

-(void)myRun
{
    while (!self.stop) {
        NSLock *arrayLock = [[NSLock alloc] init];
        [arrayLock lock];
        NSArray *message = [self.msgQueue firstObject];
        [self.msgQueue removeObjectAtIndex:0];
        [arrayLock unlock];
        NSLog(@"%@", message);
        if ([message[0] isEqualToString:@"terminate"]) {
            self.stop = YES;
        }
    }
}

-(void)join
{
    [self performSelector:@selector(myRun) onThread:self withObject:nil waitUntilDone:YES];
}

@end

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        MyClass *a = [[MyClass alloc] init];
        [a.msgQueue addObject:@[@"terminate",@"hello world"]];
        //[a myRun];   // this line works so the myRun method should be good,
        [a join];      // but I want this line work, and I have no idea what the problem is.
    }
    return 0;
}
like image 290
Kun Hu Avatar asked Feb 20 '26 12:02

Kun Hu


1 Answers

From Apple's documentation on performSelector:onThread:withObject:waitUntilDone::

This method queues the message on the run loop of the target thread using the default run loop modes—that is, the modes associated with the NSRunLoopCommonModes constant. As part of its normal run loop processing, the target thread dequeues the message (assuming it is running in one of the default run loop modes) and invokes the desired method.

You probably never started a run loop on the thread, so it will never execute your myRun method, since it has no run loop to execute on.

As for Merlevede's answer, myRun is not enqueued on the same thread as join. join was called on your main thread, whereas you're trying to enqueue myRun on your secondary thread. So his theory is incorrect. Also from Apple's documentation regarding the wait parameter:

If the current thread and target thread are the same, and you specify YES for this parameter, the selector is performed immediately on the current thread. If you specify NO, this method queues the message on the thread’s run loop and returns, just like it does for other threads. The current thread must then dequeue and process the message when it has an opportunity to do so.

So even if it was on the same thread, it wouldn't be stuck waiting, it would just execute it right away as if you had directly called the method instead of using performSelector: in the first place.

like image 184
Gavin Avatar answered Feb 22 '26 01:02

Gavin