Kappe
Kappe

Reputation: 9515

Objective-c verify the current execution thread and, in case, re execute the method in the correct thread

I'm trying to create a single method for check what is the current thread and if it is different from the desired one, re-execute the (caller) method in the right thread.

I am using:

-(void)aMethod:(id)aParam
{
   [self executeInRightThread];
   ...
}

This is the current code:

-(void)executeInRightThread
{
    NSString * rightQueueLabel = [NSString stringWithCString:dispatch_queue_get_label(myQueue) encoding:NSUTF8StringEncoding];
    NSString * currentQueueLabel = [NSString stringWithCString:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) encoding:NSUTF8StringEncoding];
    BOOL isInTheRightQueue = [currentQueueLabel isEqualToString:rightQueueLabel];

    NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1]; // Example: 1   UIKit 0x00540c89 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
    NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"];
    NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString  componentsSeparatedByCharactersInSet:separatorSet]];
    [array removeObject:@""];

//    NSLog(@"Stack = %@", [array objectAtIndex:0]);
//    NSLog(@"Framework = %@", [array objectAtIndex:1]);
//    NSLog(@"Memory address = %@", [array objectAtIndex:2]);
//    NSLog(@"Class caller = %@", [array objectAtIndex:3]);
//    NSLog(@"Function caller = %@", [array objectAtIndex:4]);
//    NSLog(@"Line caller = %@", [array objectAtIndex:5]);
    NSString * callerMethodName = [array objectAtIndex:4];

    if ( !isInTheRightQueue )
    {
        dispatch_async(myQueue, ^{
            [self performSelector:NSSelectorFromString(callerMethodName)];
        });
    }
}

The executeInRightThread method works well but I don't know how to retrieve the caller method parameters (aParam in the example), I don't want pass the parameters to the executeInRightThread method, the main aim is create something usable everywhere, without using blocks and without pass different parameters.

Upvotes: 0

Views: 349

Answers (1)

Airsource Ltd
Airsource Ltd

Reputation: 32642

Use NSThread currentThread to query the current thread. However, your question is a little confused, because you then specify the variable isInTheRightQueue.

You cannot query the current queue - dispatch_get_current_queue() is deprecated, and will not always return what you expect (and dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) has exactly the same problem). We ran into a case on iOS 8 where AVCaptureVideoOutput was configured to call us back on the main queue. In the call back, we found that the return result of dispatch_get_current_queue() was not what we expected (we originally called setSampleBufferDelegate:... queue:dispatch_get_main_queue(), but instead was:

(lldb) po dispatch_get_current_queue()
<OS_dispatch_queue: com.apple.avfoundation.videodataoutput.bufferqueue[0x170118e40] = { xrefcnt = 0x1, refcnt = 0x3, suspend_cnt = 0x0, locked = 1, target = com.apple.main-thread[0x1001be800], width = 0x0, running = 0x0, barrier = 1 }>
(lldb) p  (char*)dispatch_queue_get_label(nil)
(char *) $4 = 0x000000017026f8c0 "com.apple.avfoundation.videodataoutput.bufferqueue"
(lldb) p (char*)dispatch_queue_get_label((dispatch_queue_t)[captureOutput sampleBufferCallbackQueue])
(char *) $6 = 0x00000001001af6b0 "com.apple.main-thread"

Notice that this is a queue targeting the main thread, rather than the main queue itself.

There is no mapping between queues and threads. Any queue that executes on a background thread - as opposed to the main thread - can execute on ANY background thread.

The normal case where you want to check the execution thread is if you need to execute code which affects the UI.

if(![NSThread isMainThread])
{
    dispatch_sync(dispatch_get_main_queue(), ^{ .... });
}

If you need to verify that you have been called back on the correct background queue, then you may need to think more clearly about your application logic. However, if you really need to do this, why not do a dispatch_async to the relevant background queue. This will delay execution of your desired task, but since you're already in the background, this presumably doesn't matter.

Upvotes: 3

Related Questions