Search code examples
iosswiftuilabelnsattributedstringnsmutableattributedstring

Emoji loss when using NSMutableAttributedString on UILabel


I have got some strange problem while using NSMutableAttributedString for setting text part on UILabel. It shows some bizarre symbol for specific emojis. Here's the code i use and the screenshot of the problem.

guard var _comment = comment.comment ,let _username = comment.userName else { return }
var username = NSMutableAttributedString.init(string: _username)
var commentText = NSMutableAttributedString.init(string: _comment)
var commentTotal = NSMutableAttributedString.init()
commentTotal.append(username)
commentTotal.append(commentText)
self.userNameLabel.attributedText = commentTotal

Screenshot :

enter image description here

But if i directly put the string without using NSMutableAttributedString like this:

self.userName.text = _comment

The output of this shows the correct emoji without problem .What would be the problem here? Anyone with a suggestion? enter image description here

This is the code for setting fonts :

if let font = UIFont.init(name: "Montserrat-Bold", size: self.userNameLabel.font.pointSize){
        username.addAttribute(NSFontAttributeName, value: font, range: NSRange.init(location: 0, length: _username.count))
        username.addAttribute(NSForegroundColorAttributeName, value: UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0), range: NSRange.init(location: 0, length: _username.count))
    }



if let font = UIFont.init(name: "Montserrat-Medium", size: self.userNameLabel.font.pointSize-1){
                    commentText.addAttribute(NSFontAttributeName, value: font, range: NSRange.init(location: 0, length: commentString.count))
                    commentText.addAttribute(NSForegroundColorAttributeName, value: UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0), range: NSRange.init(location: 0, length: commentString.count))
                }

Storyboard Image: enter image description here


Solution

  • Your problem is with your NSRange calculations when setting the attributes. NS[Mutable]AttributeString needs the NSRange to be based on NSString ranges, not String ranges.

    So code like:

    NSRange.init(location: 0, length: commentString.count)
    

    Needs to be written as either:

    NSRange(location: 0, length: (commentString as NSString).length)
    

    or:

    NSRange(location: 0, length: commentString.utf16.count)
    

    The following demonstrates the issue with commentString.count:

    let comment = "💃👍👍"
    print(comment.count) // 3
    print((comment as NSString).length) // 6
    print(comment.utf16.count) // 6
    

    This is why your code seems to be splitting the middle character in half. You are passing in half (in this case) the needed length.