完成处理程序被调用两次(使用线程)

Nep*_*eph 0 ios completionhandler swift ios-multithreading dispatch-queue

我目前正在 Xcode 10 Playground (Swift 5) 中测试此代码:

func one() {
    let test = "bla"
    two(test, completion: { (returned) in
        print(returned)
        })
}

func two(_ test: String, completion: @escaping (_ returned: String?) -> Void) {
    DispatchQueue.global(qos:.background).async {
        if !test.isEmpty {
            //Some slow stuff
            DispatchQueue.main.async {
                return completion("hi!")

            }
        }

        //Also some slow stuff
        DispatchQueue.main.async {
            return completion(nil) //can't have this in "else"!
        }
    }
}

one()
Run Code Online (Sandbox Code Playgroud)

问题是“hi”和“nil”都被打印了。

如果我摆脱线程,它工作得很好,但有了它,它似乎在DispatchQueue.main.async第一个线程有机会返回之前到达第二个线程。

在我的实际代码中的“一些缓慢的东西”中还有很多事情发生,if但我不能依赖在调用第二次返回之前花费足够长的时间来返回。

如何实现这一点:让函数在后台线程中运行,但在主线程上仅返回一次(就像通常没有线程的代码一样)?

vac*_*ama 6

我相信您的目标是只调用completion处理程序一次,当您这样做时,您就完成了。在这种情况下,请return.background主线程上对完成调用进行排队后在线程中调用:

func two(_ test: String, completion: @escaping (_ returned: String?) -> Void) {
    DispatchQueue.global(qos:.background).async {
        if !test.isEmpty {
            //Some slow stuff

            // notify main thread we're done
            DispatchQueue.main.async {
                completion("hi!")
            }

            // we are done and don't want to do more work on the
            // background thread
            return
        }

        //Also some slow stuff
        DispatchQueue.main.async {
            completion(nil)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)