如何防止NSTextStorage赋值后inlinePresentationIntent属性丢失?
问题:NSAttributedString的.inlinePresentationIntent属性赋值到textStorage后丢失
在Swift开发中,我通过NSAttributedString(markdown:)加载了一段Markdown字符串,需要将该富文本转换回纯Markdown文本。为实现这个功能,我尝试枚举.inlinePresentationIntent属性来定位带有强调格式的子字符串,但遇到了问题:初始的NSAttributedString能识别加粗部分,但将其赋值给textView的textStorage后,.inlinePresentationIntent属性就消失了。
示例代码
let attributedString = try! NSAttributedString(markdown: "first **second**") let fullRange = NSRange(location: 0, length: attributedString.length) attributedString.enumerateAttribute(.inlinePresentationIntent, in: fullRange) { attribute, _, _ in print(attribute) // 输出nil和Optional(2) } textView.textStorage?.setAttributedString(attributedString) textView.textStorage!.enumerateAttribute(.inlinePresentationIntent, in: fullRange) { attribute, _, _ in print(attribute) // 输出nil }
观察结果
该问题仅出现在.inlinePresentationIntent属性上。若替换为.presentationIntentAttributeName,代码运行结果符合预期。
解决方案
1. 改用presentationIntentAttributeName枚举属性
UITextView的textStorage在处理富文本时,会保留presentationIntentAttributeName属性,但可能会过滤掉.inlinePresentationIntent(这是iOS 15+引入的别名属性,底层未被textStorage完全兼容)。直接使用原属性键即可解决问题:
// 替换枚举的属性键为presentationIntentAttributeName textView.textStorage!.enumerateAttribute(.presentationIntentAttributeName, in: fullRange) { attribute, _, _ in print(attribute) // 正常输出对应格式标识 }
2. 手动保留并重新应用属性(可选)
如果必须依赖.inlinePresentationIntent,可以在赋值到textStorage前,先提取所有该属性的范围和对应值,赋值完成后再重新为textStorage添加这些属性:
let attributedString = try! NSAttributedString(markdown: "first **second**") let fullRange = NSRange(location: 0, length: attributedString.length) // 提前保存所有.inlinePresentationIntent属性的范围和值 var intentAttributes: [(range: NSRange, value: Any?)] = [] attributedString.enumerateAttribute(.inlinePresentationIntent, in: fullRange) { value, range, _ in if let value = value { intentAttributes.append((range: range, value: value)) } } // 赋值到textStorage textView.textStorage?.setAttributedString(attributedString) // 重新应用属性 intentAttributes.forEach { item in textView.textStorage?.addAttribute(.inlinePresentationIntent, value: item.value, range: item.range) } // 此时枚举即可获取到属性 textView.textStorage!.enumerateAttribute(.inlinePresentationIntent, in: fullRange) { attribute, _, _ in print(attribute) // 正常输出nil和Optional(2) }
推荐使用第一种方案,因为它更符合系统API的兼容逻辑,无需额外的属性保存和重写操作。
内容的提问来源于stack exchange,提问作者Kaunteya
相关产品推荐
相关产品推荐

