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)")
            }
        }
        
    }
}

Your question has been asked and answered here, and so I suggest that you follow up in that thread, if needed.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

What is your custom transformer class? Since NSAttributedString isn't automatically transformed, you need to create your own one. Something like this will suffice:

class AttributedStringToDataTransformer: NSSecureUnarchiveFromDataTransformer {
    override class var allowedTopLevelClasses: [AnyClass] {
        [NSAttributedString.self]
    }

    override class func transformedValueClass() -> AnyClass {
        NSAttributedString.self
    }

    override class func allowsReverseTransformation() -> Bool {
        true
    }
}

extension NSValueTransformerName {
    static let attributedStringToDataTransformer = NSValueTransformerName("AttributedStringToDataTransformer")
}

The name of the transformer you set in the Core Data editor would be "AttributedStringToDataTransformer", and the custom class would be "NSAttributedString".

And then you need to register this custom transformer before initialising your persistent container with Core Data.

ValueTransformer.setValueTransformer(AttributedStringToDataTransformer(), forName: .attributedStringToDataTransformer)



The second point is converting between NSAttributedString and AttributedString. You can make things easier by adding a property of type AttributedString to your Item class that does the conversion.

@NSManaged private var attributedString: NSAttributedString?

public var notesText: AttributedString {
    get {
        attributedString.map(AttributedString.init) ?? ""
    } set {
        attributedString = NSAttributedString(newValue)
    }
}

You can then use this property directly in SwiftUI, and even bind the text editor to it. For example:

@State private var notesText: AttributedString = ""

// Load text
init(item: Item) {
    self.item = item
    self._notesText = State(initialValue: item.notesText)
}

// Save text
func saveButtonTapped() {
    item.notesText = notesText
    try? managedObjectContext.save()
}


Hope this helps and solves your issue.

Crash with NSAttributedString in Core Data
 
 
Q