美文网首页程序员
NSMutableAttributedString emoji

NSMutableAttributedString emoji

作者: Lee_dev | 来源:发表于2020-09-09 00:05 被阅读0次
Simulator Screen Shot - iPhone SE -2nd generation- - 2020-09-08 at 21.05.54.png

最近遇到一个坑,设置富文本时,只有一个emoji的时候,居然不显示。如上图
第一个 emoji 代码

let str = "😁"
let att = NSMutableAttributedString.init(string: str)
att.addAttributes([.foregroundColor: UIColor.red, .font: UIFont.systemFont(ofSize: 100)], range: NSMakeRange(0, str.count))

let label = UILabel()
label.textAlignment = .center
label.attributedText = att
label.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height / 2.0)
self.view.addSubview(label)

第二个 emoji 代码

let str2 = "😁"
let att2 = NSMutableAttributedString.init(string: str2)
att2.addAttributes([.foregroundColor: UIColor.red, .font: UIFont.systemFont(ofSize: 100)], range: NSMakeRange(0, str2.utf16.count))

let label2 = UILabel()
label2.textAlignment = .center
label2.attributedText = att
label2.frame = CGRect(x: 0, y: self.view.frame.height / 2.0, width: self.view.frame.width, height: self.view.frame.height / 2.0)
self.view.addSubview(label2)

二者的差别在于 utf16

NSMakeRange(0, str.count)
NSMakeRange(0, str2.utf16.count)

那么问题来了,什么是 string.utf16.count

于是,做了如下尝试:

let string = "😁"
print("string.count:\(string.count)")
print("string.utf8.count:\(string.utf8.count)")
print("string.utf16.count:\(string.utf16.count)")
print("string.utf8CString.count:\(string.utf8CString.count)")

得到结果如下:

string.count: 1
string.utf8.count: 4
string.utf16.count: 2
string.utf8CString.count: 5

😁 为什么在 utf8 长度是4, 在 utf16 下长度是2, 在 utf8CString 长度是 5 ?

请前排小板凳坐好....

String 其实是一个字符集合。

emoji起源于日本,苹果在 iOS 5 输入法中加入了emoji

emojiUnicode 位于 \u1F601-\u1F64F 区段的字符,

这个显然超过了 UTF-8 字符集的编码范围 \u0000-\uFFFF

那么 UTF-8 如何表示 emoji ?

15995777145137.jpg

比如这个 emoji 占了 4 个字节 F0 9F 98 81
所以

😁.utf8.count = 4
😁.utf16.count = 2

那么在 swift 中选哪个呢,继续往下看:

let str = "😁"
let utf8array = Array(str.utf16)
let utf8Count = str.utf8.count
print("utf8array: \(utf8array)")
print("utf8Count: \(utf8Count)")

let utf16array = Array(str.utf16)
let utf16Count = str.utf16.count
print("utf16array: \(utf16array)")
print("utf16Count: \(utf16Count)")

结果如下

utf8array: [55357, 56833]
utf8Count: 4
utf16array: [55357, 56833]
utf16Count: 2
characters: ["😁"]

显而易见,在富文本中遇到用到 count 时,如果用 utf8.count,数组会越界。

然而,是否意味着应该选择 utf16.count (不会越界) ?

继续探索,String.count 的注释

 /// The number of characters in a string.
    public var count: Int { get }

在看 NSRange_NSRange 的别名

public typealias NSRange = _NSRange

再深入查看 _NSRange

public struct _NSRange {

    public var location: Int

    public var length: Int

    public init()

    public init(location: Int, length: Int)
}

NSString 长度的介绍

The number of UTF-16 code units in the receiver.
@property(readonly) NSUInteger length;

猜测 NSMutableAttributedString, NS 开头继承 NSObject ,当我们调用

let att = NSMutableAttributedString.init(string: str)

String 或被转换成 NSString类型,

所以:

string.utf8.count 会越界, string.utf16.count 正常。

有待进一步探索。未完待续......


引用资料:

https://getemoji.com/

https://developer.apple.com/documentation/foundation/nsstring/1414212-length?language=objc

https://github.com/apple/swift/blob/master/stdlib/public/core/String.swift

相关文章

网友评论

    本文标题:NSMutableAttributedString emoji

    本文链接:https://www.haomeiwen.com/subject/xcysektx.html