SteppingHat
SteppingHat

Reputation: 1362

Can't insert NSAttributedString into NSTextView

Previously I've been able to use the following code to place attributed text into an NSTextView field

[[self->content textStorage] appendAttributedString:contentString];

However, upon updating to the Xcode 6 Beta to develop for Yosemetie, what used to work now gives me this error:

2014-08-26 11:06:06.635 JaxWire[59482:1765389] An uncaught exception was raised
2014-08-26 11:06:06.636 JaxWire[59482:1765389] Modifications to the layout engine must not be performed from a background thread.

and a whole much more globety gloop that I don't think has much use.

To give context as to how it works, a user enters text in a field, triggers a method called GO in the class InterfaceManager which then runs the following code to spawn a new thread ProcessQuery in the AppDelegate class, which is where I am attempting to change the content of NSTextView with an attributed string

[NSThread detachNewThreadSelector:@selector(processQuery:) toTarget:self withObject:query];

It's worth noting that this works if I use a standard string by executing [self->content setString:@"String"]; but when it comes to using an attributed string, it doesn't work.

How would I go about fixing this problem?

Thanks in advance! :)

Upvotes: 0

Views: 1669

Answers (2)

Brad Allred
Brad Allred

Reputation: 7534

it has nothing at all to do with Xcode. You are explicitly asking for this to be done on a background thread by using [NSThread detachNewThreadSelector], and as has been pointed out in comments, this is not allowed. You have never been "allowed" to modify the UI from a background thread, but often you could do so without noticeable problems. Yosemite is likely just enforcing this more strictly than previous versions of OS X.

I suppose the reason it works with setString: is because setString: probably doesn't immediately call the layout engine and rather the next drawing pass on the main thread does that.

you either have to not detach processQuery to a background thread, or have processQuery call appendAttributedString on the main thread using something like:

[[self->content textStorage] performSelector:@selector(appendAttributedString:) withObject: contentString]

or using GCD dispatch_async() with the main thread's queue dispatch_get_main_queue()

Upvotes: 1

Dima
Dima

Reputation: 23624

Try editing the string on the main thread instead:

dispatch_async(dispatch_get_main_queue(), ^()
{
    [[self->content textStorage] appendAttributedString:contentString];
});

Upvotes: 2

Related Questions