A curious case of NSAttributedString
Foreword
If you encounter problems of properly setting/adding attributes to NSAttributedString while the string is composed of multibyte character sets, or MBCS for short, then this article is for you.
What’s the problem?
This case happened when I was reviewing a pull request issued by my colleague. The problem was that a word in a sentence could not be properly shown with font weight .medium
.
The sentence was composed of Traditional Chinese characters. To fulfill certain UI requirements UITextView
was used instead of UILabel
. func addAttributes([NSAttributedString.Key: Any], range: NSRange)
was used to add attributes to an NSMutableAttributedString
and set to the property attributedString
of a UITextView
instance. The goal is to show a message, such as “This is a sentence.” with one or more words bold. For instance, “This is a sentence.”
The same way works onUILabel
along with its attributedString
property. However, in the case of UITextView
and Traditional Chinese just didn’t work as expected. Suppose the message is: “這是一個『測試字串』”, which means “This is a ‘string for testing’”, and I want to show it as “這是一個『測試字串』”. What came out on UI was “這是一個『測試字串』”. The same attributed string assigned to an UILabel
instance, then what came out was “這是一個『測試字串』” — That’s nonsense!
By printing the attributed string, the ranges of the attributes were correct:
mutableString: 這是一個『{NSColor = "UIExtendedGrayColorSpace 0 1";NSFont = "<UICTFont: 0x7ffe388043e0> font-family: \".SFUIText\"; font-weight: normal; font-style: normal; font-size: 15.00pt";}測試字串{NSFont = "<UICTFont: 0x7ffe38808080> font-family: \".SFUIText-Medium\"; font-weight: normal; font-style: normal; font-size: 15.00pt";}』。{NSColor = "UIExtendedGrayColorSpace 0 1";NSFont = "<UICTFont: 0x7ffe388043e0> font-family: \".SFUIText\"; font-weight: normal; font-style: normal; font-size: 15.00pt";}
That’s weird.
I also tried to add an attribute to the sentence with a given NSRange
through NSMakeRange(0, 1)
, something weird happened — That’s nonsense too!
So, what would happen to English sentences? It seems that both UILabel
and UITextView
are working fine.
What!?
Okay? Then what’s next?
Then we started to try to work around this.
Firstly, I asked my colleague to try to set the font explicitly to a font what support Traditional Chinese. PingFangTC-Regular
and PingFangTC-Medium
were given as the font for the sentence and to the word we wanted to emphasize. Although this worked, yet we could not align the font used in the same UI when the system language is not Traditional Chinese.
Next, I tried to add space before and after the symbol 『 and 』. As a result, it worked fine:
I was not satisfied with the outcome, and I tried another way by changing the content to這是一個『\0測試字串\0
to avoid the leading and trailing spaces. Surprisingly, it worked as well:
Okay, we’ve got workarounds for the problem. Finally, my colleague decided to adopt the “adding-space” one, considering that our Project manager is the one who provides localized strings. Adding \0
might be confusing.
I put an archived Xcode playground to my Google drive to elucidate this problem, you may download it through the link: https://drive.google.com/open?id=1F4lsmR-yHWE4Sj7QVczStaIgvOJQuV3D
Conclusion
In sum, it seems that UITextView
’s attributed
is buggy while working with MBCS contents. As my colleagues are going to WWDC, we are going to clarify this issue during the Lab session. Before being clarified, we would continue our work with the workarounds we’ve found. If you are getting into the same problem, I hope my experience may give you little help. Cheers!