Objective-c验证当前执行线程,并在以下情况下,在正确的线程中重新执行该方法

时间:2015-01-22 14:08:46

标签: ios objective-c multithreading

我正在尝试创建一个方法来检查当前线程是什么,如果它与所需的线程不同,请在右侧线程中重新执行(调用方)方法。

我正在使用:

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

这是当前的代码:

-(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)];
        });
    }
}

executeInRightThread方法运行良好,但我不知道如何检索调用方法参数(示例中的aParam),我不希望将参数传递给executeInRightThread方法,主要目标是创建可在任何地方使用的东西,不使用块而不传递不同的参数。

1 个答案:

答案 0 :(得分:3)

使用NSThread currentThread查询当前线程。但是,您的问题有点困惑,因为您随后指定了变量isInTheRightQueue

您无法查询当前队列 - dispatch_get_current_queue()已弃用,并且不会始终返回您期望的内容(并且dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)具有完全相同的问题)。我们在iOS 8上遇到了一个案例,其中AVCaptureVideoOutput被配置为在主队列上回调我们。在回调中,我们发现dispatch_get_current_queue()的返回结果与我们预期的不同(我们最初称为setSampleBufferDelegate:... queue:dispatch_get_main_queue(),而是:

(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"

请注意,这是一个以主线程为目标的队列,而不是主队列本身。

队列和线程之间没有映射。在后台线程上执行的任何队列 - 与主线程相反 - 都可以在任何后台线程上执行。

您要检查执行线程的正常情况是您是否需要执行影响UI的代码。

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

如果您需要验证是否已在正确的后台队列中回调,那么您可能需要更清楚地思考应用程序逻辑。但是,如果您确实需要这样做,为什么不对相关的后台队列执行dispatch_async。这将延迟执行您想要的任务,但由于您已经在后台,这可能并不重要。