Skip to content

Commit

Permalink
Fix deadlock running tests in Xcode 16
Browse files Browse the repository at this point in the history
Fixes #56
  • Loading branch information
stephan-tolksdorf committed Sep 29, 2024
1 parent 1345701 commit 12cceed
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 9 deletions.
5 changes: 5 additions & 0 deletions STULabel/STUMainScreenProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ STU_DISABLE_CLANG_WARNING("-Wunguarded-availability")
STU_REENABLE_CLANG_WARNING
};

/// This function is normally executed automatically when the library is loaded from an Objective C @c load initialization method.
/// If this leads to issues, you can define an @c STULabel_NoMainScreenPropertiesInitializationOnLoad environment variable
/// and then call this function explicity from the main thread before using any of the STULabel functionality.
void stu_initializeMainScreenProperties(void);

/// Returns the value of @c UIScreen.main.fixedCoordinateSpace.bounds.size.
/// Thread-safe.
CGSize stu_mainScreenPortraitSize(void);
Expand Down
41 changes: 32 additions & 9 deletions STULabel/STUMainScreenProperties.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,12 @@ static void updateMainScreenProperties(void) {
#undef store
}

@interface UIScreen (STUMainScreenProperties)
+ (void)load;
@end
@implementation UIScreen (STUMainScreenProperties)
+ (void)load {
// We can't do this initialization lazily, because UIScreen must only be accessed on the
// main thread. (Using `dispatch_sync(dispatch_get_main_queue(), ...)` would lead to a
// deadlock when the main thread is waiting for the thread in which stu_mainScreen... is called
// for the first time.)
void stu_initializeMainScreenProperties(void) {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
updateMainScreenProperties();
#if !STU_MAIN_SCREEN_PROPERTIES_ARE_CONSTANT
NSNotificationCenter * const notificationCenter = NSNotificationCenter.defaultCenter;
Expand All @@ -81,6 +78,32 @@ + (void)load {
usingBlock:updateMainScreenPropertiesBlock];
#endif
}

@interface UIScreen (STUMainScreenProperties)
+ (void)load;
@end
@implementation UIScreen (STUMainScreenProperties)
+ (void)load {
// We can't do this initialization lazily, because UIScreen must only be accessed on the
// main thread. (Using `dispatch_sync(dispatch_get_main_queue(), ...)` would lead to a
// deadlock when the main thread is waiting for the thread in which stu_mainScreen... is called
// for the first time.)
// However, when executing this `load` method when a test bundle is loaded,
// calling stu_initializeMainScreenProperties synchronously leads to a deadlock in UIScreen.mainScreen,
// so for that special case we just invoke stu_initializeMainScreenProperties asynchronously,
// relying on the main screen properties not beeing used before stu_initializeMainScreenProperties has run.
NSDictionary* env = NSProcessInfo.processInfo.environment;
if ([env valueForKey:@"STULabel_NoMainScreenPropertiesInitializationOnLoad"]) {
return;
}
if ([env valueForKey:@"XCTestBundlePath"]) {
dispatch_async(dispatch_get_main_queue(), ^{
stu_initializeMainScreenProperties();
});
return;
}
stu_initializeMainScreenProperties();
}
@end

#if STU_MAIN_SCREEN_PROPERTIES_ARE_CONSTANT
Expand Down

0 comments on commit 12cceed

Please sign in to comment.