使用NSAttributedString
,我想在字符串的下划线下划线。以下代码无法正常工作:
let string = NSMutableAttributedString(string: "This is my string.")
string.addAttributes([.underlineStyle : NSUnderlineStyle.single],
range: NSRange(location: 5, length: 2))
人们期望“是”被强调。相反,UITextView布局引擎将忽略该属性,并在控制台中生成警告。该警告无助地没有提及
underlineStyle
或NSUnderlineStyle
。这个问题很普遍。 StackOverflow上有很多示例显示了正确的用法。但是,尽管我确定必须有一些答案来解释问题,但我已阅读的答案仅显示了用法的不透明示例。
提出这个问题(并在下面给出答案)是为了纪念对该问题的解释,以便将来我和其他人可以从中学习。
最佳答案
NSUnderlineStyle
不是正确的类型
准确但有些无助的是,documentation解释说underlineStyle
属性键采用“包含整数的NSNumber
”的属性值。
此属性的值是一个NSNumber对象,其中包含
整数。此值指示文本是否带下划线,以及
对应于NSUnderlineStyle中描述的常量之一。的
此属性的默认值为styleNone。
许多读者被NSUnderlineStyle
所吸引,点击它,然后找到一个类似于枚举的样式列表:single
,thick
,patternDash
,double
等。这似乎是一个不错的Swifty解决方案。读者认为此枚举必须是指定属性值的方式,并键入上面问题中所示的代码种类。rawValue
的NSUnderlineStyle
属性提供正确的类型NSUnderlineStyle
不是一个枚举。它是符合OptionSet
协议的结构。 OptionSet
协议是设置整数位的便捷,快速方法,每个位代表二进制状态。 NSUnderlineStyle
结构是该整数的包装器。它的类似于枚举的样式实际上是结构上的静态var,每个静态var返回带有嵌入式整数的NSUnderlineStyle
实例,只有一位翻转以对应于所需样式。NSAttributedString
的属性字典将字面意义上的任何内容作为值,因此它很乐意接受NSUnderlineStyle
的实例。但是使UITextView
和UILabel
工作的引擎TextKit不知道如何处理NSUnderlineStyle
实例。当TextKit尝试呈现underlineStyle
属性时,它需要一个整数,以便可以通过检查整数的位来确定正确的样式。
幸运的是,有一种简单的方法可以获取该整数。 rawValue
的NSUnderlineStyle
属性对其进行出售。因此,我们的代码段的正常工作版本如下:
let string = NSMutableAttributedString(string: "This is my string.")
string.addAttributes([.underlineStyle : NSUnderlineStyle.single.rawValue],
range: NSRange(location: 5, length: 2))
该代码与问题代码之间的唯一区别是在“NSUnderlineStyle.single”上添加了“.rawValue”。并且,“是”下划线。
另外,
rawValue
属性提供的类型是Int
,而不是NSNumber
。文档对属性值为NSNumber
的引用可能会造成混淆。在底层,为了与ObjC互操作,NSAttributedString
将Int
包装在NSNumber
中。不需要(或没有好处?)将Int
显式包装在NSNumber
中。使用
OptionSet
union
方法合并下划线样式我们可以将多个下划线样式组合成一个复合样式。在按位级别上,这是通过对表示两种样式的整数进行逻辑或来实现的。作为
OptionSet
,NSUnderlineStyle
提供了Swifty替代方案。 union(_:)
上的NSUnderlineStyle
方法以更简单的英语方式实现逻辑或。举个例子:NSUnderlineStyle.double.union(.patternDot).rawValue
这段代码将生成一个
Int
,并翻转了相应的位,TextKit绘制了一个非常漂亮的虚线双下划线。当然,并不是所有的组合都能工作。 'NSAttributedString'可以接受任何内容,但是常识和TextKit
引擎最终将决定。