Applying temporaryAttributes from processEditing (_fillGlyphHoleForCharacterRange: crash)
Applying temporaryAttributes from processEditing (_fillGlyphHoleForCharacterRange: crash)
- Subject: Applying temporaryAttributes from processEditing (_fillGlyphHoleForCharacterRange: crash)
- From: Keith Blount <email@hidden>
- Date: Tue, 6 Oct 2009 09:20:03 -0700 (PDT)
Hello,
I’m attempting to add temporary attributes (all of which do not require layout) to text as soon as it has been edited if it has a custom attribute applied (much how the text system automatically applies linkTextAttributes to any text with an NSLinkAttributeName attribute - although from my various tests and NSLogging it seems that the text system does that under the hood using some internal magic and doesn’t use temporary attributes). In another thread on a related issue Aki Inoue was kind enough to point out that I could override NSLayoutManager’s -showPackedGlyphs:etc... to change the colour of the text, but that doesn’t handle underlines or strikethroughs, for which I still need to apply temporary attributes.
My current solution is to try to override my custom text storage’s -processEditing method to iterate through the layout managers and apply any necessary temporary attributes there, something like this:
- (void)processEditing
{
[super processEditing];
NSRange dirtyRange = [self editedRange];
if (dirtyRange.length == 0)
return;
NSEnumerator *e = [[self layoutManagers] objectEnumerator];
NSLayoutManager *lm;
while (lm = [e nextObject])
{
if (dirtyRangeHasMyCustomAttribute)
[lm addTemporaryAttributes:tempAttribs forCharacterRange:dirtyRange];
}
}
However, the above has massive problems. In certain circumstances it causes this crash:
-[KBLayoutManager _fillGlyphHoleForCharacterRange:startGlyphIndex:desiredNumberOfCharacters:] *** attempted glyph generation while textStorage is editing. It is not valid to cause the layoutManager to do glyph generation while the textStorage is editing (ie the textStorage has been sent a beginEditing message without a matching endEditing.)
I’m not entirely sure why, as I’ve NSLogged all of the beginEditing and endEditing messages and this code is only ever call after the last -endEditing, so beginEditing and endEditing should are matching (I even tested it out by putting it into -endEditing and processing things only after calling [super endEditing] but had the same crash).
I can avoid the crash by putting the temporary attribute application code into a separate method and calling it after a zero delay like this:
- (void)processEditing
{
[super processEditing];
[self performSelector:@selector(applyTempAttributesIfNecessaryToRange:) withObject:[NSValue valueWithRange:[self editedRange] afterDelay:0];
}
But this seems fragile to me. I’m not entirely sure why calling the same code after a delay of 0 would prevent the crash, or confident that it will work in all situations.
Has anyone tried to do something similar and found a better solution to what I’m trying to do?
Many thanks in advance and all the best,
Keith
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden