Reputation: 920
When the app starts, I want to update my current database. Sometimes not all the data gets saved and some data is missing.
I am doing the save with this function:
func save1() {
let group = DispatchGroup()
for a in save.oldVersion.defaExchangesEinzeln {
if save.checkForVersionExchange(exchange: a.key) {
group.enter()
save.saveVersionExchanges(exchange: a.key)
save.storeContainer.performBackgroundTask{ context in
self.save.saveDefAExchange(managedContext: context, exchange: a.key)
try? context.save()
group.leave()
}
}
}
for b in save.oldVersion.fdefCoinstBtc {
if save.checkForVersionFdefCoinsTBTC(exchange: b.key) {
save.saveVersionFdefCoinsTBTC(exchange: b.key)
}
}
for c in save.oldVersion.fdefCoinstUsd {
if save.checkForVersionFdefCoinsTUSD(exchange: c.key) {
save.saveVersionFdefCoinsTUSD(exchange: c.key)
}
}
if save.checkForCoinNamesExall() || save.checkForVersionIconsExall() || save.checkForVersionFdefCoinsTarrExall() {
save.saveVersionOthers()
}
if save.checkForCoinNamesExall() {
group.enter()
storeContainer?.performBackgroundTask{ context in
self.save.saveCoinNames(managedContext: context)
do {
try context.save()
} catch let error {
print(error.localizedDescription)
}
group.leave()
}
}
if save.checkForVersionIconsExall() {
group.enter()
storeContainer?.performBackgroundTask { context in
self.save.saveIcons(managedContext: context)
do {
try context.save()
} catch let error {
print(error.localizedDescription)
}
group.leave()
}
}
if save.checkForVersionFdefCoinsTarrExall() {
group.enter()
storeContainer?.performBackgroundTask { context in
self.save.saveGroups(context)
do {
try context.save()
} catch let error {
print(error.localizedDescription)
}
group.leave()
}
}
group.notify(queue: .main) {
print("Update complete 1")
self.delegateWebsocket?.startWebsocket()
}
}
I can imagine that due to the async call the contexts somehow conflict with each other. Why does it happen? What can I do to improve the code? Thanks!
Upvotes: 0
Views: 548
Reputation: 70966
Using performBackgroundTask
can be incredibly convenient but it has a sharp edge that's not always apparent at first. Every time you call performBackgroundTask
, a new context is created, and the block you pass in executes on that context's private queue. The block is executed asynchronously.
The upshot is that if you call performBackgroundTask
repeatedly in a loop, as you are, there's no guarantee that the blocks will be synchronized relative to each other. That can be a problem.
There are a couple of approaches you could take to deal with this. I'm not sure I'm following all of your code so I'm not sure which might be best. Alternatives include:
performBackgroundTask
instead of creating a bunch of background tasks. Or possibly just reduce the number of tasks by putting performBackgroundTask
outside your initial loop instead of inside.performBackgroundTask
. Instead, create a single background context and use that. Get a new context using newBackgroundContext()
and keep it around. Then replace your background tasks above with perform
or performAndWait
calls on that context.Upvotes: 1