Xcode 26: Sendable checking + NSManagedObjectContext.perform in Swift 6

I have some code which handles doing some computation on a background thread before updating Core Data NSManagedObjects by using the NSManagedObjectContext.perform functions.

This code is covered in Sendable warnings in Xcode 26 (beta 6) because my NSManagedObject subclasses (autogenerated) are non-Sendable and NSManagedObjectContext.perform function takes a Sendable closure.

But I can't really figure out what I should be doing. I realize this pattern is non-ideal for Swift concurrency, but it's what Core Data demands AFAIK. How do I deal with this?

let moc = object.managedObjectContext!
try await moc.perform {
    object.completed = true // Capture of 'object' with non-Sendable type 'MySpecialObject' in a '@Sendable' closure
    try moc.save()
}

Thanks in advance for your help!

Answered by DTS Engineer in 855095022

You can capture the managed object ID (NSManagedObjectID) instead, which is Sendable:

let moc = object.managedObjectContext!
let objectID = object.objectID
try await moc.perform {
    let object = mac.object(with: objectID)
    object.completed = true
    try moc.save()
}

Note that mac.object(with: objectID) may trigger a fetch, which is fine if you don't run the piece of code many times – If you do, you might consider refactoring your code to avoid that. As an example, if you have a loop that runs that piece of code a lot of times, you can move the loop into the perform block.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

You can capture the managed object ID (NSManagedObjectID) instead, which is Sendable:

let moc = object.managedObjectContext!
let objectID = object.objectID
try await moc.perform {
    let object = mac.object(with: objectID)
    object.completed = true
    try moc.save()
}

Note that mac.object(with: objectID) may trigger a fetch, which is fine if you don't run the piece of code many times – If you do, you might consider refactoring your code to avoid that. As an example, if you have a loop that runs that piece of code a lot of times, you can move the loop into the perform block.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Xcode 26: Sendable checking + NSManagedObjectContext.perform in Swift 6
 
 
Q