Overview of Attribute Fixing in NSTextStorage

NSTextStorage provides attribute fixing of user-entered text, via NSMutableAttributedString.fixAttributes(in:).

Attribute fixing…

  • … applies font fallbacks to special characters not included in the text font, e.g. “ZapDingbats” for some Unicode symbols, or “AppleColorEmoji” for Emoji display
    • “assigns default fonts to characters with illegal fonts for their scripts and otherwise corrects font attribute assignments”1
  • … makes all characters in a paragraph inherit the paragraph style
    • “assigns the first paragraph style attribute value in each paragraph to all characters of the paragraph”1
  • … removes attachment attributes for any character in range that is not NSTextAttachment.character1

NSMutableAttributedString.fixAttributes(in:) always work on full paragraph ranges. It extends the passed-in range as needed “to cover the last paragraph partially contained”1.

Attribute fixing is automatically applied from NSTextStorage.processEditing() via invalidateAttributes(in:) “when the text storage changes”.2

The attribute fixing mechanism can be applied eagerly or lazily:

  1. Eager attribute fixing
    • Requires subclassing: fixesAttributesLazily has to return false. The default, when you initialize a standard NSTextStorage (i.e. the concrete hidden subclass), is true. When you subclass, the default is false.
    • Makes invalidateAttributes(in:) call NSMutableAttributedString.fixAttributes(in:) directly (eagerly).
  2. Lazy attribute fixing
    • Default behavior of the system default concrete NSTextStorage subclass.
    • Makes invalidateAttributes(in:) enqueue the range for later instead of processing it immediately.
    • Internally requires ensureAttributesAreFixed(in:) calls before any attribute access. This in turn processes enqueued invalidated ranges.
    • Internally requires subclasses to “avoid directly calling fixAttributes(in:) or else bracket such calls with beginEditing() and endEditing() messages.”1
  1. Apple API docs: NSMutableAttributedString.fixAttributes(in:), https://developer.apple.com/documentation/foundation/nsmutableattributedstring/1533823-fixattributes, accessed 2022-09-21  2 3 4 5

  2. Apple API docs: NSTextStorage.invalidateAttributes(in:), https://developer.apple.com/documentation/uikit/nstextstorage/1534025-invalidateattributes, accessed 2022-09-21