You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何防止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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 05:42:34