在主线程上运行方法的宏



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

目前,我有这样的东西:

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

但我想要一种方法将其包含在宏中,而无需输入该方法的参数。似乎应该有某种方法来迭代传递给当前方法的参数列表并创建 NSInvocation 或类似内容。有什么想法吗?

这行得通吗?

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

如果您也从主线程调用它,这也将起作用,这是一个奖励。如果需要异步调用,只需使用 dispatch_async 而不是 dispatch_sync 即可。

与其

尝试在不同的线程上重新调用您的方法,我建议使用 dispatch_sync()dispatch_get_main_queue() 来确保只有敏感代码在主线程上。这可以很容易地包装在一个函数中,就像Brad Larson对"GCD在主线程中执行任务"的回答一样。

他的过程本质上与您已有的过程相同,区别在于代码被放入一个块中,并根据需要调用或排队:

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

如果使用 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.
    });
}

归因:灵感来自理查德·罗斯的回答

我知道从

这样的方法创建动态 NSInvocation 的唯一方法需要您的方法的参数是va_list。

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

我认为这就是您要查找的:

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

相关内容

最新更新