1

My MacOS Cocoa application displays a window of static text, meaning it should not be changed by the user, should not be first responder, etcetera. The only thing that happens to the text is that each word of it changes color (from "idleColor" to "highlightColor", and then back again) at a specific point in time. It is similar to a Karaoke display - individual words change color, and then change back, under program control, based on a list of timed events.

All of this works beautifully under MacOS 10.7 and 10.8. BUT, under 10.9, the text color does NOT change UNLESS I click in the window and continually move the cursor around, so I am manually highlighting (and un-highlighting) some of the text, continuously. If I do this, the regular words behave as intended. Essentially, it feels like the OS is refusing to update the window under program control, unless I am forcing it to update by manually performing something that requires the UI to respond.

The code that performs the color changes is as follows:

if (sEvent.attribute == HIGHLIGHT_ON) {
    [sTextView setTextColor:highlightColor range: currentRange];
    textIsLitUp = YES;
    }
else {
    [sTextView setTextColor:idleColor range: currentRange];
    textIsLitUp = NO;
    }
[sTextView setNeedsDisplay:YES];

(sTextView is a subclass of NSTextView.)

Now, if I comment out that last line, then I get the same, incorrect behavior under 10.7 and 10.8. In other words, under 10.9, the setNeedsDisplay method is not working, or not working the same way.

Does anyone have any ideas about working around this, or have any other light to shed on the problem? Or am I doing something terribly wrong? It is CRITICAL to the application that the changes to the textColor happen without latency!

EDITING MY QUESTION - to answer it:

Found the answer elsewhere here! I needed to call setNeedsDisplay on the main thread - it was in a secondary thread. The weird thing is that it always seemed to work fine under 10.7 and 10.8. It only broke under 10.9. So I just changed this:

[myTextField setNeedsDisplay:YES];

To this:

dispatch_async(dispatch_get_main_queue(), ^{[myTextField setNeedsDisplay:YES];});

…and it seem to have worked. Hope this helps someone else…</p>

4

1 回答 1

2

你不想在非主线程中对 AppKit 对象进行任何更改——它有时会工作,甚至可能经常工作,但每隔一段时间它就会崩溃,你会想知道为什么。所以:

[sTextView setTextColor:idleColor range: currentRange];

也需要在主线程上。

于 2014-01-28T08:22:56.190 回答