Crash with NSAttributedString in Core Data

I am trying out the new AttributedString binding with SwiftUI’s TextEditor in iOS26. I need to save this to a Core Data database. Core Data has no AttributedString type, so I set the type of the field to “Transformable”, give it a custom class of NSAttributedString, and set the transformer to NSSecureUnarchiveFromData

When I try to save, I first convert the Swift AttributedString to NSAttributedString, and then save the context. Unfortunately I get this error when saving the context, and the save isn't persisted:

CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x600003721140> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)

Here's the code that tries to save the attributed string:

struct AttributedDetailView: View {
@ObservedObject var item: Item
@State private var notesText = AttributedString()
var body: some View {
VStack {
TextEditor(text: $notesText)
.padding()
.onChange(of: notesText) {
item.attributedString = NSAttributedString(notesText)
}
}
.onAppear {
if let nsattributed = item.attributedString {
notesText = AttributedString(nsattributed)
} else {
notesText = ""
}
}
.task {
item.attributedString = NSAttributedString(notesText)
do {
try item.managedObjectContext?.save()
} catch {
print("core data save error = \(error)")
}
}
}
}

This is the attribute setup in the Core Data model editor:

Is there a workaround for this?

I filed FB17943846 if someone can take a look. Thanks.

NSSecureUnarchiveFromDataTransformer doesn't transform NSAttributedString for you, and so you need to provide your own transformer. I ever used the following code to transform NSAttributedString to NSData and vice versa. You can give it a try and see if that fixes your issue.

import Foundation
extension NSValueTransformerName {
static let nsAttributedStringTransformer = NSValueTransformerName(rawValue: "NSAttributedStringTransformer")
}
@objc(NSAttributedStringTransformer)
class NSAttributedStringTransformer: NSSecureUnarchiveFromDataTransformer {
override class func allowsReverseTransformation() -> Bool {
return true
}
override class var allowedTopLevelClasses: [AnyClass] {
return [NSAttributedString.self]
}
override class func transformedValueClass() -> AnyClass {
return NSAttributedString.self
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let attributedString = value as? NSAttributedString else {
return nil
}
return attributedString.toNSData()
}
override func transformedValue(_ value: Any?) -> Any? {
guard let data = value as? NSData else {
return nil
}
return data.toAttributedString()
}
}
private extension NSData {
func toAttributedString() -> NSAttributedString? {
let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
.documentType: NSAttributedString.DocumentType.rtf,
.characterEncoding: String.Encoding.utf8
]
return try? NSAttributedString(data: Data(referencing: self),
options: options,
documentAttributes: nil)
}
}
private extension NSAttributedString {
func toNSData() -> NSData? {
let options: [NSAttributedString.DocumentAttributeKey: Any] = [
.documentType: NSAttributedString.DocumentType.rtf,
.characterEncoding: String.Encoding.utf8
]
let range = NSRange(location: 0, length: length)
guard let data = try? data(from: range, documentAttributes: options) else {
return nil
}
return NSData(data: data)
}
}

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Thanks for that. I tried it, and now I can save / fetch the NSData from Core Data after transforming it ... BUT it doesn't get rendered as an attributed string (i.e. the formatting gets lost).

This is the code for the next TextEditor in iOS26 that takes an AttributedString for its binding. Is there something wrong that I'm doing?

struct AttributedDetailView: View {
@ObservedObject var item: Item
@State private var notesText = AttributedString()
var body: some View {
VStack {
TextEditor(text: $notesText)
.padding()
.onChange(of: notesText) {
item.attributedString = NSAttributedString(notesText).toNSData()
}
}
.onAppear {
if let nsattributed = item.attributedString?.toAttributedString() {
notesText = AttributedString(nsattributed)
} else {
notesText = ""
}
}
.onDisappear {
item.attributedString = NSAttributedString(notesText).toNSData()
do {
try item.managedObjectContext?.save()
} catch {
print("core data save error = \(error)")
}
}
}
}
Crash with NSAttributedString in Core Data
 
 
Q