Search code examples
iosuitextviewnsattributedstringuifontnstextstorage

Set new font at end of NSTextStorage NSMutableAttributedString


I'm writing an app that deals with rich text editing using a UITextView. It uses NSTextStorage to set new attributes for parts of the string. However, in the case that the user wants to change the font or font size at the end of the string for a new style of text or in the middle of the string (in other words when range passed to setAttributes:range: has a length of 0) this can't be done because you can't set attributes with a range of 0. So basically, how can I set a new UIFont for the position of the cursor in a UITextView?

relevant code from my NSTextStorage subclass:

- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range
{
NSLog(@"setAttributes:%@ range:%@", attrs, NSStringFromRange(range));

[self beginEditing];
[_backingStore setAttributes:attrs range:range];

[_backingStore fixAttributesInRange:range];

[self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
[self endEditing];
}

Solution

  • Fixed it! What I ended up doing was adding an instance variable tempAttributes to my NSTextStorage subclass. If I tried to set the attributes of a string with range 0, I set tempAttributes to the attributes being passed in. Then on the next pass of the method, if tempAttributes had data, I set the range it was trying to change with that instead of the old attributes. New code:

    - (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range
    {
        NSLog(@"setAttributes:%@ range:%@", attrs, NSStringFromRange(range));
    
    [self beginEditing];
    if (range.location == _backingStore.length || range.length == 0) {
        tempAttributes = attrs;
    } else {
        if (tempAttributes) {
            [_backingStore setAttributes:tempAttributes range:range];
            tempAttributes = nil;
        } else {
            [_backingStore setAttributes:attrs range:range];
        }
    }
    
    [_backingStore fixAttributesInRange:range];
    
    [self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
    [self endEditing];
    }