Search code examples
iosswiftuitextviewnsattributedstring

NSAttributedString from UTF16 characters in UITextView


I have the following code to make a hyperlink for a string within a UITextView

extension UITextView {
  func setAttributed(text: String) {
    self.attributedText = text.htmlAttributedString()
  }
}

extension String {
  func htmlAttributedString(document: NSAttributedString.DocumentType = .html) -> NSAttributedString? {
    guard let data = self.data(using: .utf16, allowLossyConversion: false), let font = font else { return nil }
    do {
      return try NSMutableAttributedString(data: data, options: [.documentType: document, .characterEncoding: String.Encoding.utf16.rawValue], documentAttributes: nil)
    } catch {
      debugger("error in string conversion. \(error.localizedDescription)")
      return nil
    }
}

And it is call like: self.messageTextView.setAttributed(text: "<a href=\"\(utf16_str1)\">\(utf16_str2)</a>")

It is working fine when the text contains only simple utf8 characters and returns the following result:

text {
    NSColor = "kCGColorSpaceModelRGB 0 0 0.933333 1 ";
    NSFont = "<UICTFont: 0x1056bd910> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 12.00pt";
    NSKern = 0;
    NSLink = "https://google.com";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 15/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n), DefaultTabInterval 36, Blocks (\n), Lists (\n), BaseWritingDirection 0, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";
    NSStrokeColor = "kCGColorSpaceModelRGB 0 0 0.933333 1 ";
    NSStrokeWidth = 0;
    NSUnderline = 1;
}

However, when text contains utf16 characters such as ä or ö, the result is broken as below:

<a href="https://google.com">textäö</a>{
    NSFont = "<UICTFont: 0x109f0eb30> font-family: \".SFUI-Regular\"; font-weight: normal; font-style: normal; font-size: 12.00pt";
}

How can I fix the issue so strings with chars like ä don't break the result


Solution

  • Apparently, strings with non-ascii characters have to be normalized before such use cases. The issue is resolved using precomposedStringWithCanonicalMapping as documented here: https://developer.apple.com/documentation/foundation/nsstring/1412645-precomposedstringwithcanonicalma.