完成处理程序会结束功能吗?

时间:2020-01-30 22:49:50

标签: swift completionhandler

也许我不了解完成处理程序的概念,但是我有一个类似的功能;

func someFunction(completion: @escaping (Bool, LoginError?) -> Void) {
    self.checkDevice() { allowed, error in
       if let e = error {
          completion(false, e)
       }
        completion(true, nil)
    }
}

了解checkDevice()的功能时,基本前提是它执行异步网络调用,并返回没有错误(nil)的 true 或返回错误并显示错误。

运行此代码时,我发现完成处理程序被调用了两次。它以元组(false, error)和(true, nil)的形式发送完成。我已经进行了一些调试,似乎没有办法两次调用someFunction()

我相信,一旦发送完成,该功能就会结束。在我的测试案例中,我强制执行checkDevice()中的错误,这应该导致我将完成发送为(false, error,但是我同时看到了{false, error)和({{ 1}})。完成不会立即结束功能吗?

3 个答案:

答案 0 :(得分:3)

我相信一旦发送完成,功能就会结束。

不,为什么会这样?当您调用此函数时,就像调用任何其他函数一样。 名称没有魔力。

像这样重写它:

func someFunction(completion: @escaping (Bool, LoginError?) -> Void) {
    self.checkDevice() { allowed, error in
        if let e = error {
            completion(false, e)
            return // *
        }
        completion(true, nil)
    }
}

实际上,我应该提到,这是编写完成处理程序的糟糕方法。与其采用两个参数(布尔型和一个可选的LoginError)(仅当布尔型为false时才使用),它应该采用一个 one 参数-一个Result,它包含我们成功还是失败并且,如果失败了,错误是什么:

func someFunction(completion: @escaping (Result<Void, Error>) -> Void) {
    self.checkDevice() { allowed, error in
        completion( Result {
            if let e = error { throw e }
        })
    }
}

如您所见,使用Result作为参数可以使您对发生的事情更加优雅。

实际上,checkDevice本身可以将Result传递给完成处理程序,这样事情就会变得更加优雅(更简单)。

答案 1 :(得分:1)

完成处理程序不会结束函数。结束函数的典型方法是插入 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if indexPath.row == 0{ return 0 } return tableView.rowHeight }

查看评论重新:您的具体情况

答案 2 :(得分:1)

考虑包括参数名称(供参考)。完成只能调用一次。您可以使用return或使用完整的if-else条件来做到这一点。

func someFunction(completion: @escaping (_ done: Bool, _ error: LoginError?) -> Void) {

    checkDevice() { (allowed, error) in

        if let e = error {
            completion(false, e)
        } else {
            completion(true, nil)
        }

    }

}

func someFunction(completion: @escaping (_ done: Bool, _ error: LoginError?) -> Void) {

    checkDevice() { (allowed, error) in

        if let e = error {

            completion(false, e)
            return

        }

        completion(true, nil)

    }

}

通过提供参数名称,在调用函数时,您现在可以引用签名来表示其参数的含义:

someFunction { (done, error) in

    if let error = error {
        ...
    } else if done {
        ...
    }

}