Reputation: 831
I am measuring text block heights in a background thread. For some reason, if this happens when the application has just started, the thread makes a call to a NSColor subclass called DynamicColor
which needs to be in main thread, as it checks if the app is in dark mode or not.
The class where the background thread is running should not have any reference to DynamicColor
, but still, when the NSTextStorage
is allocated, DynamicColor gets called. It causes an error for making UI calls from background task.
I have no idea how the NSTextStorage
could be making call to some class it doesn't know to exist. Only my NSDocument
subclass has referral to it, none of the other classes should be unaware of it.
Call to background thread in NSDocument
:
- (void)updatePreviewAndUI:(bool)updateUI {
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
Preview *preview = [[PreviewCreator alloc] initWithScript:script];
});
}
The background thread goes over numerous elements containing string data and calculates their heights.
+ (NSInteger)heightForString:(NSString *)string font:(NSFont *)font maxWidth:(NSInteger)maxWidth lineHeight:(CGFloat)lineHeight
{
// The error occurs here
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:string attributes:@{NSFontAttributeName: font }];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(maxWidth, MAXFLOAT)];
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];
...
}
Call to DynamicColor
happens when NSTextStorage
is allocated. I was able to avoid crashes by checking if we are on the main thread in DynamicColor
, but I'm worried about the cause of the error.
DynamicColor
is a NSColor
subclass. Here are the relevant parts:
#define FORWARD( PROP, TYPE ) \
- (TYPE)PROP { return [self.effectiveColor PROP]; }
- (NSColor *)effectiveColor
{
if (NSApp) {
// Call to Application delegate causes the thread error
if ([(ApplicationDelegate*)[NSApp delegate] isForcedLightMode]) {
if (self.aquaColor != nil) return self.aquaColor;
}
else if ([(ApplicationDelegate*)[NSApp delegate] isForcedDarkMode]) {
if (self.darkAquaColor != nil) return self.darkAquaColor;
}
}
}
I tried setting a plain NSColor
as the NSTextContainer
foreground color, but it didn't help. The error does not occur every time when running the app, and in a test environment I was unable to reproduce the problem. Also, it's only the first time a text container is allocated, when this happens.
Upvotes: 0
Views: 51