确保函数仅在主线程上运行

时间:2022-02-20 21:03:50

How can I make sure that my function is run only on the main thread? (It updates UI elements)
Is a function like this considered 'bad'?

如何确保我的函数仅在主线程上运行? (它更新UI元素)这样的函数被认为是“坏”吗?

-(void)updateSomethingOnMainThread {
if ( ![[NSThread currentThread] isEqual:[NSThread mainThread]] )
    [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];
else {
    // Do stuff on main thread
}
}

I wrote it like this to avoid having a second function, initially I had it like this:

我这样写它是为了避免有第二个功能,最初我有这样的:

-(void)updateSomethingOnMainThread_real {
    // Do stuff on main thread
}

-(void)updateSomethingOnMainThread {
    [self performSelectorOnMainThread:@selector(updateSomethingOnMainThread_real) withObject:nil waitUntilDone:NO];
}

4 个解决方案

#1


8  

This is fine. You can also use GCD to execute code on the main thread.

这可以。您还可以使用GCD在主线程上执行代码。

Checkout this SO post.

查看此SO帖子。

GCD to perform task in main thread

GCD在主线程中执行任务

#2


15  

As an alternative to ayoy's method-based GCD implementation for guaranteeing execution on the main thread, I use the following GCD-based function in my code (drawn from another answer of mine):

作为ayoy基于方法的GCD实现的替代方案,用于保证在主线程上的执行,我在我的代码中使用了以下基于GCD的函数(从我的另一个答案中得出):

void runOnMainThreadWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

You can then use this helper function anywhere in your code:

然后,您可以在代码中的任何位置使用此辅助函数:

runOnMainThreadWithoutDeadlocking(^{
    // Do stuff that needs to be on the main thread
});

This guarantees that the actions taken in the enclosed block will always run on the main thread, no matter which thread calls this. It adds little code and is fairly explicit as to which code needs to be run on the main thread.

这保证了封闭块中的操作将始终在主线程上运行,无论哪个线程调用它。它添加了很少的代码,并且明确指出需要在主线程上运行哪些代码。

#3


5  

I wrote this simple #define which I've been using with great success:

我写了这个简单的#define,我一直在使用它非常成功:

#define ensureInMainThread(); if (!NSThread.isMainThread) { [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];    return; }

That way your method, assuming it's parameterless, looks like this

这样你的方法,假设它是无参数的,看起来像这样

- (void) updateTheThings {
      ensureInMainThread();
      [self.dog setTailWag:YES];
      // etc...

#4


3  

Alternatively, you can use Grand Central Dispatch API, but it's not very handy:

或者,您可以使用Grand Central Dispatch API,但它不是很方便:

-(void)updateSomethingOnMainThread {
    void (^doStuff)(void) = ^{
        // stuff to be done
    };

    // this check avoids possible deadlock resulting from
    // calling dispatch_sync() on the same queue as current one
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    if (mainQueue == dispatch_get_current_queue()) {
        // execute code in place
        doStuff();
    } else {
        // dispatch doStuff() to main queue
        dispatch_sync(mainQueue, doStuff);
    }
}

otherwise, if synchronous call isn't needed, you can call dispatch_async() which is much simpler:

否则,如果不需要同步调用,则可以调用dispatch_async(),这更简单:

-(void)updateSomethingOnMainThread {
    dispatch_async(dispatch_get_main_queue(), ^{
        // do stuff
    });
}

#1


8  

This is fine. You can also use GCD to execute code on the main thread.

这可以。您还可以使用GCD在主线程上执行代码。

Checkout this SO post.

查看此SO帖子。

GCD to perform task in main thread

GCD在主线程中执行任务

#2


15  

As an alternative to ayoy's method-based GCD implementation for guaranteeing execution on the main thread, I use the following GCD-based function in my code (drawn from another answer of mine):

作为ayoy基于方法的GCD实现的替代方案,用于保证在主线程上的执行,我在我的代码中使用了以下基于GCD的函数(从我的另一个答案中得出):

void runOnMainThreadWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

You can then use this helper function anywhere in your code:

然后,您可以在代码中的任何位置使用此辅助函数:

runOnMainThreadWithoutDeadlocking(^{
    // Do stuff that needs to be on the main thread
});

This guarantees that the actions taken in the enclosed block will always run on the main thread, no matter which thread calls this. It adds little code and is fairly explicit as to which code needs to be run on the main thread.

这保证了封闭块中的操作将始终在主线程上运行,无论哪个线程调用它。它添加了很少的代码,并且明确指出需要在主线程上运行哪些代码。

#3


5  

I wrote this simple #define which I've been using with great success:

我写了这个简单的#define,我一直在使用它非常成功:

#define ensureInMainThread(); if (!NSThread.isMainThread) { [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];    return; }

That way your method, assuming it's parameterless, looks like this

这样你的方法,假设它是无参数的,看起来像这样

- (void) updateTheThings {
      ensureInMainThread();
      [self.dog setTailWag:YES];
      // etc...

#4


3  

Alternatively, you can use Grand Central Dispatch API, but it's not very handy:

或者,您可以使用Grand Central Dispatch API,但它不是很方便:

-(void)updateSomethingOnMainThread {
    void (^doStuff)(void) = ^{
        // stuff to be done
    };

    // this check avoids possible deadlock resulting from
    // calling dispatch_sync() on the same queue as current one
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    if (mainQueue == dispatch_get_current_queue()) {
        // execute code in place
        doStuff();
    } else {
        // dispatch doStuff() to main queue
        dispatch_sync(mainQueue, doStuff);
    }
}

otherwise, if synchronous call isn't needed, you can call dispatch_async() which is much simpler:

否则,如果不需要同步调用,则可以调用dispatch_async(),这更简单:

-(void)updateSomethingOnMainThread {
    dispatch_async(dispatch_get_main_queue(), ^{
        // do stuff
    });
}