首页 > 解决方案 > 有没有办法快速确保 API 调用在竞争条件下只被调用一次

问题描述

在我的应用程序中,我需要调用一个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很多次,但这似乎是相反的问题——多个函数在一个调用上等待,而不是在函数/块上等待多个。

提前致谢

标签: iosswift

解决方案


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

该函数应在串行后台队列上同步运行其代码。这使得它不可能被两个不同的线程同时调用。这是您的伪代码的伪代码;未经测试,但它显示了我相信会起作用的东西:

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(),但否则这是可行的。


推荐阅读