Since one of conveniences that SwiftData
offers, which is automatically saving of a record when something is added or changed in the model context, does explicit calling save()
makes any difference? I guess in both cases, SwiftData
will decide?
@ModelActor
public actor DataHandler {
@discardableResult
public func new(item: Item) throws -> PersistentIdentifier {
modelContext.insert(item)
try modelContext.save()
return item.persistentModelID
}
@discardableResult
public func newEmptyItem() throws -> PersistentIdentifier {
let item = Item()
modelContext.insert(item)
try modelContext.save()
return item.persistentModelID
}
Can I remove this line:
try modelContext.save()
without any worries?
Can I remove this line without any worries?
No. From some simple experiments, it can be observed that while save
is called, it is not called synchronously with insert
. It is called asynchronously, possibly in the next run loop cycle. This makes a lot of sense, because if you are calling insert
in a loop, it is most likely good for performance, if only one save operation is performed for all those insert
s.
// suppose Foo is a @Model and ctx is a ModelContext with autosave enabled
let foo = Foo(name: "foo")
ctx.insert(foo)
// this prints true, and a non-empty array, showing that the newly inserted model is not saved
print(ctx.hasChanges, ctx.insertedModelsArray)
// let's get the model's ID at this point and save it for later
let id = foo.persistentModelID
var retrievedFoo: Foo? = ctx.registeredModel(for: id)
print(retrievedFoo) // this prints non-nil, as expected
// wait for a while to let 'save' be automatically called
try! await Task.sleep(for: .milliseconds(100))
// this prints false, []
// showing that save has indeed been called
print(ctx.hasChanges, ctx.insertedModelsArray)
retrievedFoo = ctx.registeredModel(for: id)
print(retrievedFoo) // this prints nil, showing that the old ID no longer works
As demonstrated above, if you remove the manual save
call, the ID you return from new
and newEmptyItem
would be a temporary ID that will become invalid after a subsequent save
call. So in this case, the manual save
matters a lot! See also the documentation for insert
:
A model is given a temporary persistent identifier until the first time a context saves it, after which that context assigns a permanent identifier.