Hello everyone,
I'm working with a User model in Swift, simplified as:
@Model
class User: Decodable {
var name: String
}
To avoid duplicating the logic of fetching the first user from the database, I've implemented a property wrapper @UserWrapper
. This wrapper fetches the user and returns it as a wrapped value. My goal is to observe any changes to the user in the database and update the views accordingly.
Here's my property wrapper:
@Observable
@propertyWrapper class UserWrapper {
var user: User? = .none
init() {
guard let container = try? ModelContainer(for: User.self) else { return }
let context = ModelContext(container)
self.user = try? context.fetch(FetchDescriptor<User>()).first
let didSaveNotification = Notification.Name.NSManagedObjectContextDidSave
NotificationCenter.default.addObserver(self, selector: #selector(didSave(_:)),
name: didSaveNotification, object: nil)
}
@objc func didSave(_ notification: Notification) {
guard let container = try? ModelContainer(for: User.self) else { return }
let context = ModelContext(container)
let insertedObjectsKey = ModelContext.NotificationKey.insertedIdentifiers.rawValue
let deletedObjectsKey = ModelContext.NotificationKey.deletedIdentifiers.rawValue
let updatedObjectsKey = ModelContext.NotificationKey.updatedIdentifiers.rawValue
if let insertedObj = notification.userInfo?[insertedObjectsKey] as? Set<NSManagedObject> {
let objectIDs = insertedObj.map(\.objectID)
}
if let deletedObj = notification.userInfo?[deletedObjectsKey] as? Set<NSManagedObject> {
print("deletedObj \(deletedObj)")
}
if let updatedObj = notification.userInfo?[updatedObjectsKey] as? Set<NSManagedObject> {
print("updatedObj \(updatedObj)")
}
}
var wrappedValue: User? {
get {
return user
}
set {
self.user = newValue
}
}
}
Is there a more efficient or cleaner approach to achieve this? Any suggestions or best practices would be greatly appreciated!