I'm subclassing NSTextStorage
to do some link highlighting and I've read as much as I can on the topic. Everything works fine until I type the π
emoji character.
My subclass:
private let ims = NSMutableAttributedString()
override var string: String {
return ims.string
}
override func attributesAtIndex(location: Int, effectiveRange range: NSRangePointer) -> [String : AnyObject] {
return ims.attributesAtIndex(location, effectiveRange: range)
}
override func replaceCharactersInRange(range: NSRange, withString str: String) {
ims.replaceCharactersInRange(range, withString: str)
self.edited(.EditedCharacters, range: range, changeInLength:(str as NSString).length - range.length)
}
override func setAttributes(attrs: [String : AnyObject]?, range: NSRange) {
ims.setAttributes(attrs, range: range)
self.edited(.EditedAttributes, range: range, changeInLength: 0)
}
Nothing complicated. Then, when entering the infamous character it switches to Courier New for some random reason:
Now I'm picking on the π
character, there are others that cause this maddness too. I've queried the font as I type and it goes from System > Apple Emoji > Courier New.
I've also tried setting the font from within processEditing()
which semi solves the problem, It causes an extra space to be added in (not in the simulator though). And I'm hardcoding a value == bad.
Ultimate Question:
What am I doing wrong? I don't see this problem with other people's implementations where I'm certain developers have subclassed NSTextStorage.
Note: I can confirm that in objc.io's demo app the same issue is present.
processEditing()
β BloodthirstyprocessEditing
as well. At least it doesn't break emojis. β JacquelinejacquelynfixAttributesInRange(range: NSRange)
is where this stuff gets determined in NSTextStorage, so that's probably the best place to work around it. Unfortunately, simply eliminating any unrecognized fonts would not work in every case, sincefixAttributesInRange
also performs font substitution for unknown characters (as it does for emoji). β HeliogravurefixAttributesInRange
) into Apple's emoji font (AppleColorEmoji). This means that anything typed after that emoji will also use that font (as expected with NSAttributedString attributes). However, AppleColorEmoji does not contain characters for ordinary letters, so the range for those letters, in turn, gets changed from AppleColorEmoji to monospace. If only there was a way to tell NSAttributedString to constrain a font only to a particular range and never grow it! β HeliogravurefixAttributes(in range: NSRange)
didn't work for me. I still get_NSLayoutTreeLineFragmentRectForGlyphAtIndex invalid glyph index 1
printed in the debugger with emojis β SaturateprocessEditing()
I apply those attributes to the range value returned byparagraphRange(for: editedRange)
before other attributes are applied. Within init I assign a font value created from the UIFontDescriptor API to defaultAttributes and viadidSet
I calledited(_: range: changeInLength:)
passing in.editedAttributes
for the editedMask. β Bloodthirsty