I am working with the rich TextEditor introduced in iOS 26, but I am having trouble preserving AttributedString formatting when converting to/from RTF.
Here is my exporting logic in my view model (AttributedString to RTF)
let nsAttrStr = NSAttributedString(self.text) // text is an AttributedString (bound to the TextEditor input)
let range = NSRange(location: 0, length: nsAttrStr.length)
let options: [NSAttributedString.DocumentAttributeKey: Any] = [
.documentType: NSAttributedString.DocumentType.rtf
]
guard let data = try? nsAttrStr.data(from: range, documentAttributes: options) else {
return nil
}
let rtfBase64 = data.base64EncodedString()
When I inspect the result, it seems to lose the font, size, boldness, etc which is being correctly rendered in the TextEditor. When I convert back from RTF to an AttributedString, it reverts to the default text formatting applied in the TextEditor.
Any ideas what could be going wrong?
Yeah, converting AttributedString
to NSAttributedString
and then to Data
with NSAttributedString.DocumentType.rtf
will lose SwiftUI attributes (because SwiftUI attributes aren't represented in an ObjC-based NSAttributedString
), unless you convert the SwiftUI attributes to UIKit / AppKit attributes with your own code.
You can convert AttributedString
directly to RTF / RTFD data using AttributedTextFormatting.Transferable, which was newly introduced in iOS 26 and friends. The following code example shows how to do that:
struct ContentView: View {
@Environment(\.self) private var environment
...
private func attributedStringToRTF() async {
var attributedString = AttributedString(inputText)
attributedString.backgroundColor = .red
print("Input: attributedString = \(attributedString)")
let transferable = AttributedTextFormatting.Transferable(text: attributedString, in: environment)
guard let rtfData = try? await transferable.exported(as: .rtf) else {
return
}
guard let transferrable2 = try? await AttributedTextFormatting.Transferable(importing: rtfData, contentType: .rtf) else {
return
}
let attributedString2 = try! AttributedString(transferable: transferrable2, in: environment)
print("Output: attributedString = \(attributedString2)")
}
}
The output:
Input: attributedString = This is test. {
SwiftUI.BackgroundColor = red
}
Output: attributedString = This is test. {
SwiftUI.BackgroundColor = UIKitPlatformColorProvider(platformColor: kCGColorSpaceModelRGB 1 0.21961 0.23529 1)
SwiftUI.Font = Font(provider: SwiftUI.FontBox<SwiftUI.Font.PlatformFontProvider>)
SwiftUI.ForegroundColor = UIKitPlatformColorProvider(platformColor: kCGColorSpaceModelRGB 0 0 0 1)
CoreText.TextAlignment = left
}
Best,
——
Ziqiao Chen
Worldwide Developer Relations.