宏在主线程上运行方法

时间:2012-06-12 23:30:50

标签: objective-c ios multithreading

我想要一种简单的方法来在方法的开头删除代码,该方法将强制该方法仅在主线程上运行(因为该方法更新了UI元素)。

目前,我有类似的内容:

 if (![NSThread isMainThread]){
    [self performSelectorOnMainThread:_cmd withObject:_results waitUntilDone:NO];
    return;
}

但是我想要一种方法将它包含在一个宏中而不必输入方法的参数。看起来应该有一些方法来迭代传递给当前方法的参数列表并创建一个NSInvocation或类似的。有什么想法吗?

5 个答案:

答案 0 :(得分:6)

这会有用吗?

#define dispatch_main($block) (dispatch_get_current_queue() == dispatch_get_main_queue() ? $block() : dispatch_sync(dispatch_get_main_queue(), $block))

如果你从主线程中调用它也会有效,这是一个奖励。 如果您需要异步调用,只需使用dispatch_async而不是dispatch_sync

答案 1 :(得分:3)

我建议使用dispatch_sync()dispatch_get_main_queue()来确保只有敏感代码在主线程上,而不是尝试在不同的线程上重新调用您的方法。这可以很容易地包含在函数中,如Brad Larson's answer to "GCD to perform task in main thread"中所示。

他的程序与你已经拥有的程序基本相同,不同之处在于代码被放入一个块中,并在适当时调用或排队:

if ([NSThread isMainThread])
{
    blockContainingUICode();
}
else
{
    dispatch_sync(dispatch_get_main_queue(), blockContainingUICode);
}

如果您愿意,也可以毫不费力地将其翻译成宏。

创建块本身不需要太多改变。如果您的UI代码如下所示:

[[self textLabel] setText:name];

[[self detailTextLabel] setText:formattedDollarValue];

[[self imageView] setImage:thumbnail];

将它放入要排队的区块中就像这样:

dispatch_block_t blockContainingUICode = ^{

    [[self textLabel] setText:mainText];

    [[self detailTextLabel] setText:detailText];

    [[self imageView] setImage:thumbnail];
};

答案 2 :(得分:1)

我知道从这样的方法创建动态NSInvocation的唯一方法是需要将方法的参数作为va_list。

您需要能够将当前方法的参数作为数组(以便您可以循环数组并将参数添加到NSInvocation中)并且我不确定这是否可行(我不是认为是)。

答案 3 :(得分:1)

如果使用NSThread条件三进制从主线程或后台线程调用此方法,它将起作用。


同步:

#define dispatch_main(__block) ([NSThread isMainThread] ? __block() : dispatch_sync(dispatch_get_main_queue(), __block))

异步:

#define dispatch_main(__block) ([NSThread isMainThread] ? __block() : dispatch_async(dispatch_get_main_queue(), __block))

要使用:

-(void)method {
    dispatch_main(^{
        //contents of method here.
    });
}

归因:受Richard Ross's Answer

的启发

答案 4 :(得分:0)

我认为这就是你要找的东西:

- (void)someMethod
{
    // Make sure the code will run on main thread

    if (! [NSThread isMainThread])
    {
        [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:YES];

        return;
    }

    // Do some work on the main thread
}