请考虑以下代码:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let validator:NSPredicate = NSPredicate(format:"SELF MATCHES %@","[A-Za-z0-9- ]+")
if(validator.evaluateWithObject(string) || string == "" /* i.e. backspace */) {
self.process(textField)
return true
}
else {
return false
}
}
我想在return语句之后实际运行self.process(textField),因为在它之前,textField中的文本实际上还没有改变。这让我想知道,为什么我不能在return语句 * 之后 * 执行一些代码?为什么函数总是在return语句发生时停止?
我知道这是return * 的传统意义,但是有没有其他的方法呢?比如,有没有一种方法可以从一个函数返回一个值,然后继续执行?
一方面,这似乎是个愚蠢的问题,但另一方面,我觉得我不可能是第一个想做这件事的人。如果我能在run循环的下一个循环中启动一些东西就足够了,所以也许GCD中有一些东西会帮助我。
6条答案
按热度按时间y4ekin9u1#
从Swift 2.0开始,我们有了一个关键字“defer”。这个关键字允许我们指定一个代码块,即函数中的一个段,它将在程序控制权被转移到作用域之外之前执行。可能是为了清理或其他需要,即使抛出错误也需要执行的操作。
defer块中的代码执行被延迟到倒数第二条语句执行完毕,假设最后一条语句是return语句。
以下是您可以使用它的方法:
defer块的位置应该放在大括号内的任何位置,并且总是放在return语句之前,这是出于逻辑原因,也是为了避免出现警告:“永远不会执行'return'之后的代码”。
以下是一些例子:
j0pj023g2#
你的问题的答案是否定的。但你的问题的解决方案很简单。
DispatchQueue.main.async
会将执行延迟到run循环的下一次迭代。使用这些print()
语句,您会在控制台中看到这一点。您的时间戳会有所不同,但您会看到微小的差异(在本例中大约为15/1000秒)。即将返回真,时间戳:1612578965.103658
即将处理textField,时间戳:1612578965.1188931
如果需要特定的延迟,请使用
DispatchQueue.main.asyncAfter
我发现最好的解释是Matt Neuburg的书“iOS 14编程基础与Swift”。
ao218c7q3#
我认为您需要将流程代码移到另一个函数中。
8gsdolmq4#
在return语句之后没有语言原语来运行任意代码。没有语言提供这一点。然而,你总是可以使用闭包来嵌入和排序代码流;就像完成处理程序一样。
在某些情况下,您可能需要使用
willSet
和/或didSet
。假设有一个String属性作为文本字段的后备存储。如果字符串通过验证,则您写入后备存储。这将触发willSet
,它可以运行您的process
代码,并根据结果直接更新textField
。0h4hbjxa5#
延迟注入应该在代码的可达语句处,否则它们将不会在代码块的末尾执行。基本上,这是延迟的主要思想。
cld4siwp6#
一旦函数返回,函数的被调用生命周期就结束了。为了保证函数返回后的第一次执行,需要调用函数的对象在序列化环境中执行该函数。
然而,在您的用例中,该函数是由用户输入调用的,除非我们对此进行子类化或混合处理,否则我建议在您的用例中使用具有不明显延迟的异步调度:
这是一个边缘黑客,我个人不喜欢这种解决方案,但替代方案是如此丑陋,从用户端,它会看起来无缝。肯定有启发式的工程空间,这是一个这样的情况。