以调用 API 为例。这个电话需要一些时间,但我们会在电话完成后做一些事情。例如,假设我们想用我们提取的新数据刷新 UITableView。如果我们立即执行此操作,则尚未收到数据:
ApiObject.getObjects(completion: { (error, objects) in })
tableView.reloadData()
如果我们在这里重新加载数据,表格视图将立即刷新(在我们实际接收到数据之前)。通过在完成块中执行它,我们是说,在我们完成函数时运行代码,而不是在函数实际返回时运行代码:
ApiObject.getObjects(completion: {(error, objects) in
self.tableView.reloadData()
})
这里我们是在获取对象后运行它,而不是在函数本身到达末尾时运行它。
编辑
也许这会让事情变得更容易;我有以下代码:
let comeInAnimation = POPBasicAnimation(propertyNamed: kPOPLayoutConstraintConstant)!
comeInAnimation.toValue = 0
comeInAnimation.completionBlock = { (anim, success) -> Void in
self.loginButton.enabled = true
self.signupButton.enabled = true
}
signUpContainingViewLeftConstraint.pop_add(comeInAnimation, forKey: AnimationString.EnterExit.identifier)
这是使用 POP 动画框架。在这种情况下,我有一个登录和注册按钮,但我也有一个动画让它们出现。我不想在按钮出现时点击它们,所以我最初将它们的启用设置为 false。现在您可以看到它们在完成块中设置为启用。这意味着,当动画完成时,完成块被调用,我知道现在是时候将它们设置为启用了。如果我这样做了:
let comeInAnimation = POPBasicAnimation(propertyNamed: kPOPLayoutConstraintConstant)!
comeInAnimation.toValue = 0
signUpContainingViewLeftConstraint.pop_add(comeInAnimation, forKey: AnimationString.EnterExit.identifier)
self.loginButton.enabled = true
self.signupButton.enabled = true
即使启用的属性是在调用动画之后设置的,但这些属性实际上是在动画完成之前设置的。因为程序逐行运行,所以添加了动画,然后立即设置属性(这还为时过早)。
注意:这是一个问题,因为这些函数是异步运行的。也就是说,它允许程序在执行其操作时继续运行。如果这行代码被阻塞(停止程序直到它完成),那么将代码放在完成块中并立即将其放在后面将是同一件事。但在现实生活中,我们不想阻止,因为它给人的感觉是程序已冻结。