有没有一种迅速的方法来确保在竞争条件下一次API调用仅被调用一次

时间:2019-06-24 22:41:34

标签: ios swift

在我的应用程序中,我需要调用一个getGroup()函数,该函数使用用户信息联系我们的CMS,然后根据该信息和CMS中当前的内容将它们放在一个组中。该组信息包含在我们其他API调用的URL中。

问题在于,当应用程序启动且尚未缓存用户组时,每个API调用都会触发getGroup实际进行API调用,而不仅仅是获取缓存的组。我想减少它,以使调用仅进行一次,而对该函数的其他调用则等到听到响应为止。

我想做的伪代码示例:

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
        }
    }
}

我尝试过使用信号灯,但是我认为我需要一些更全球化的东西,例如NotificationCenter的帖子。我的主要问题是根据通知暂停单个函数调用,而不是等待分配的时间。我已经使用DispatchGroups很多次了,但这似乎是相反的问题-多个函数在一个调用上等待,而不是函数/块在多个调用上等待。

预先感谢

1 个答案:

答案 0 :(得分:1)

  

该调用仅进行一次,其他对该函数的调用将等待直到听到响应为止

该函数应在串行后台队列上同步运行其代码。这使得不可能由两个不同的线程同时调用它。这是您的伪代码的伪代码;未经测试,但显示出我认为可以使用的功能:

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()
    }
}

我不确定是否需要派遣小组,但我已将其放置在sync范围内。

编辑:OP指出实际上是需要派遣组的,您需要说出g.wait()而不是notify(),但这是可行的。