NSAttributedString attributes stripped after assigning to NSTextStorage

124 views Asked by At

In the code below, I am loading a markdown string in NSAttributedString. One of the feature in the app needs functionality to convert NSAttributedString back to plain markdown text. To achieve that, I am trying to find substrings with emphasis by enumerating the . inlinePresentationIntent attribute.

In the code below, the NSAttributedString takes the bold part of the string into account. However, when I assign it to the NSTextStorage, the inlinePresentationIntent attribute disappears

let attributedString = try! NSAttributedString(markdown: "first **second**")

attributedString.enumerateAttribute(.inlinePresentationIntent, in: fullRange) { a, _, _ in
    print(a) /////////////////// Prints nil and Optional(2)
}

textView.textStorage?.setAttributedString(attributedString)

textView.textStorage!.enumerateAttribute(.inlinePresentationIntent, in: fullRange) { a, _, _ in
    print(a) ///////////////////// Prints nil
}

How do I prevent the inlinePresentationIntent attribute from disappearing after assigning it to the textStorage?


Observation:

This happens only with .inlinePresentationIntent. If I replace .inlinePresentationIntent with .presentationIntentAttributeName then the code works as expected

1

There are 1 answers

0
Willeke On

Duplicate the .inlinePresentationIntent attribute into a custom attribute before setting textStorage. Use this custom attribute to convert the string back to markdown text.

extension NSAttributedString.Key {
    static var myMarkdownAttribute: NSAttributedString.Key {
        NSAttributedString.Key("myMarkdownAttribute")
    }
}

let mutableAttributedString = try! NSMutableAttributedString(markdown: "first **second**")
mutableAttributedString.enumerateAttribute(.inlinePresentationIntent, in: NSRange(location: 0, length: mutableAttributedString.length)) { attributeValue, range, _ in
    if let attributeValue = attributeValue {
        mutableAttributedString.addAttribute(.myMarkdownAttribute, value: attributeValue, range: range)
    }
}