Reputation: 11
In my app, I need to call a getGroup()
function that reaches out to our CMS using user information, and places them in a group depending on that info and content currently in the CMS. This group info is included in the URL of our other API calls.
The problem is that when the app starts and the user's group isn't cached yet, each of these API calls trigger getGroup to actually make the API call instead of just getting the cached group. I'd like to reduce it so the call is only made once, and the other calls to the function wait until a response is heard.
Pseudocode example of what I would like to do:
var isGettingGroup = false
func getGroup(completion: (group?, error?)) {
if isGettingGroup {
wait for notification
}
if let group = groupFromCache() {
completion(group, nil)
} else {
isGettingGroup = true
callGetGroupAPI() { group, error in
completion(group, error)
cacheGroup(group)
isGettingGroup = false
send notification to continue
}
}
}
I've tried using a semaphore, but I think I need something a bit more global, like a post from NotificationCenter
. My main problem is pausing the individual function call depending on a notification instead of waiting for an allotted amount of time. I've used DispatchGroups
many times, but this seems like the opposite problem - multiple functions waiting on one call, instead of on function/block waiting on multiple.
Thanks in advance
Upvotes: 0
Views: 1084
Reputation: 535890
the call is only made once, and the other calls to the function wait until a response is heard
The function should run its code on a serial background queue synchronously. This makes it impossible for it to be called simultaneously by two different threads. Here's a pseudocode of your pseudocode; untested, but it shows something I believe will work:
let q = DispatchQueue()
func getGroup(completion: (group?, error?)) {
q.sync { // lock out any other calls to getGroup until we finish
let g = DispatchGroup()
g.enter()
if let group = groupFromCache() {
completion(group, nil)
g.leave()
} else {
callGetGroupAPI() { group, error in
completion(group, error)
cacheGroup(group)
g.leave()
}
}
g.notify()
}
}
I'm not entirely sure the dispatch group is needed but I've put it in to keep everything within the bounds of the sync
.
EDIT The OP says that the dispatch group is in fact needed, and you need to say g.wait()
instead of notify()
, but otherwise this works.
Upvotes: 1