I’m using MessageManager::callAsync for incoming midi messages to trigger functions on the message thread.
But now I want some of these functions to be triggered after a delay. Is it enough in this case to just use Timer::callAfterDelay and not use MessageManager::callAsync at all? It seems to work just fine but I’m not sure if it’s correct.
Timer::callAfterDelay clamps the delay at one milli second. So its not entirely the same, but you shouldn’t expect it to be accurate on more than 5ms anyway, so it should be good enough.
The implementation of Timer::callAfterDelay is super easy to understand.
A one-shot lambda wrapper inheriting from juce::Timer.
And if you ask yourself about delete this< Standard C++ >
IMHO except for sporadic usage, i would prefer to use a custom one, to avoid the ctor/dtor at each incoming midi message for instance.
But that’s just a vague premature-optimized opinion…
But please aware of the usage with both of them. Care should be taken to make sure that the captured members in the lambda does not get deleted when the lambda gets executed.
When I use it in a juce::Component context, I do like,
// An extension to juce's callAfterDelay which also checks if the component is being present before calling the function
struct safeCallAfterDelay : private Timer
{
safeCallAfterDelay(int milliseconds, std::function<void()> f, Component* component)
: function(std::move(f))
, checker(component)
{
startTimer(milliseconds);
}
void timerCallback() override
{
if (checker.shouldBailOut()) //Checks if the GUI object has been deleted
delete this;
else
{
auto f = function;
delete this;
f();
}
}
std::function<void()> function;
juce::Component::BailOutChecker checker;
};
When in need, I do something like, new safeCallAfterDelay(3000, [&]{compAssociated.doSomething(); }, &compAssociated)
When using callAsync I captured a const reference sent to the function which was calling callAsync and experienced crashes which was then solved after I captured it by value.