umutg4d
umutg4d

Reputation: 239

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

Upvotes: 9

Views: 2133

Answers (2)

Milan NosáΔΎ
Milan NosáΔΎ

Reputation: 19747

Proper way to do this in Swift 4 is using indexes on String:

NSRange(location: 0, length: commentString.endIndex.encodedOffset)

Upvotes: 3

rmaddy
rmaddy

Reputation: 318824

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.

Upvotes: 25

Related Questions