
最近遇到一个坑,设置富文本时,只有一个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。
emoji在 Unicode 位于 \u1F601-\u1F64F 区段的字符,
这个显然超过了 UTF-8 字符集的编码范围 \u0000-\uFFFF
那么 UTF-8 如何表示 emoji ?

比如这个 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://developer.apple.com/documentation/foundation/nsstring/1414212-length?language=objc
https://github.com/apple/swift/blob/master/stdlib/public/core/String.swift
网友评论