SwiftData: Solving Fatal Errors and EXC_BAD_ACCESS While Handling Entities on Different Threads
Tags: swift, swiftdata, concurrency
Published: 2024-04-11 12:26:28

_I just wanted to start out by saying that this is an abridged version of my [original published version from December 22, 2023 that you can find on my website here](https://www.simplykyra.com/swiftdata-solving-fatal-errors-and-exc_bad_access-while-handling-entities-on-different-threads/)._

---

Part of the back end code of one of my apps is composed of asynchronous functions that I call and then await their returned results. When moving my apps over from `CoreData` to `SwiftData` the data context that used to be passed into each function was dropped and I noticed it didn't act consistently anymore. The main problems were:

**EXC_BAD_ACCESS**

The first error I had was a generalized `EXC_BAD_ACCESS (code=1, address=...)` that showed up mainly in my entry App @Main struct but also popped up at various entity relationships spots all under various thread count numbers.

![Image shows the EXC_BAD_ACCESS error on a relationship](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tn5fgh87c17eixeb5fkz.png)

**Fatal Error: Duplicate Keys**

At some point in all of this when I couldn't figure out how to fix the issue I decided to at least help mitigate it by manually saving the data context after each related entity was done being created. I figured this way if the program crashed at least the data that had been created before that point would be saved and the user wouldn't have to start back at the beginning each time. This didn't help as once I added saving, at any of the points, I got fatal errors on my entities complaining about duplicate keys.

```
Fatal error: Duplicate keys of type 'EntityName' were found in a Dictionary.
This usually means either that the type violates Hashable's requirements, or that members of such a dictionary were mutated after insertion.
```

**The Solution**

To solve this I realized I needed to stop passing in the main data entity and instead pass in it's `PersistentIdentifier` along with it's `ModelContext` so it can be recreated in the asynchronous and/or problematic functions. This worked! 

So, for example, if I used pass in the entity directly to a function like:

```
private func doSomething(entity: EntityName, ...) async {
   // ... doing whatever happened to the entity
}
```

I'd now call the new method with `doSomething(in: entity.modelContext!.container, entityID: entity.persistentModelID, ...)` instead and the function itself would look like:

```
private func doSomething(in container: ModelContainer, entityID: PersistentIdentifier, ...) async {
   // First recreate the main entity in it's own ModelContext
   let modelContext = ModelContext(container)
   modelContext.autosaveEnabled = false
   let entity = modelContext.model(for: entityID) as? EntityName
   if entity == nil {
      // Can't continue without entity
      // TODO: Handle any error handling and...
      return
   }

   // ... doing whatever happened to the entity

   do {
      try modelContext.save()
   } catch {
      // It can't be saved
      // TODO: Handle any error handling and...
      return
   }
   // Success!
}
```

With the different data context used in my problematic asynchronous methods both my fatal and bad access errors are gone!

If you want more information about how I solved this along with a quick stop in concurrency check out [my original version published in December 22, 2023](https://www.simplykyra.com/swiftdata-solving-fatal-errors-and-exc_bad_access-while-handling-entities-on-different-threads/) on my main website.

Have a great day!