Add `ModelContext` API to gracefully fetch a model by its ID

Originator:darren.mo
Number:rdar://FB13457226 Date Originated:2023-12-08
Status:Open Resolved:
Product:SwiftData Product Version:iOS 17.2 RC Seed (21C62)
Classification:Suggestion Reproducible:
 
`ModelContext` currently has two methods to fetch a model by ID: `model(for:)` and `registeredModel(for:)`. The latter only returns a model that is already in the context. The former may fetch a model from the model container in addition to the context, but it crashes if the model was not found.

There should be a third method, similar to `NSManagedObjectContext.existingObject(with:)`, that can fetch a model from the model container but does not crash if the model was not found. Or, perhaps `model(for:)` should be updated to not crash.

One use case for such an API would be passing a model ID across concurrency domains. The receiver might use that model ID to fetch the model from the model context/container. However, since this is in a different concurrency domain, the model could have been deleted by the time the receiver tried to fetch the model. This is an expected edge case that should gracefully return `nil` or throw an error rather than crashing.

Example implementation:
```
extension ModelContext {
   func model<T: PersistentModel>(for persistentModelID: PersistentIdentifier) throws -> T? {
      if let model: T = registeredModel(for: persistentModelID) {
         return model
      }

      var fetchDescriptor = FetchDescriptor<T>(
         predicate: #Predicate {
            $0.persistentModelID == persistentModelID
         }
      )
      fetchDescriptor.fetchLimit = 1

      return try fetch(fetchDescriptor).first
   }
}
```

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!