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 protected])

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to