Introducing smart `RCTUnsafeExecuteOnMainQueueOnceSync()` and fixed `RCTScreenScale()`

Summary:
(This diff was decoupled from D4983054 which landing was quite delayed.)

`RCTUnsafeExecuteOnMainQueueOnceSync()` synchronously executes a block once, on main queue.
I found that our old implementation of `RCTScreenScale()` causes deadlock when it is called from main and background thread simultaneously.
After I implemented my own solution I googled this issue and found an article by Ben Alpert with this awesome helper:
https://benalpert.com/2014/04/02/dispatch-once-initialization-on-the-main-thread.html
So, I found it super useful and borrowed it.

Hey spicyj! :)

Reviewed By: fkgozali

Differential Revision: D5632592

fbshipit-source-id: dff43a5780b7404a3cc109c66c131cef4f4df429
This commit is contained in:
Valentin Shergin 2017-08-15 14:05:22 -07:00 committed by Facebook Github Bot
parent 274f10feb4
commit a7468a4acf
1 changed files with 20 additions and 5 deletions

View File

@ -264,14 +264,29 @@ void RCTUnsafeExecuteOnMainQueueSync(dispatch_block_t block)
}
}
static void RCTUnsafeExecuteOnMainQueueOnceSync(dispatch_once_t *onceToken, dispatch_block_t block)
{
// The solution was borrowed from a post by Ben Alpert:
// https://benalpert.com/2014/04/02/dispatch-once-initialization-on-the-main-thread.html
// See also: https://www.mikeash.com/pyblog/friday-qa-2014-06-06-secrets-of-dispatch_once.html
if (RCTIsMainQueue()) {
dispatch_once(onceToken, block);
} else {
if (DISPATCH_EXPECT(*onceToken == 0L, NO)) {
dispatch_sync(dispatch_get_main_queue(), ^{
dispatch_once(onceToken, block);
});
}
}
}
CGFloat RCTScreenScale()
{
static CGFloat scale;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
RCTUnsafeExecuteOnMainQueueSync(^{
scale = [UIScreen mainScreen].scale;
});
static CGFloat scale;
RCTUnsafeExecuteOnMainQueueOnceSync(&onceToken, ^{
scale = [UIScreen mainScreen].scale;
});
return scale;