swift2 如何在Swift中运行函数中return语句之后的代码?

uqxowvwt  于 2022-11-06  发布在  Swift
关注(0)|答案(6)|浏览(197)

请考虑以下代码:

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中有一些东西会帮助我。

y4ekin9u

y4ekin9u1#

从Swift 2.0开始,我们有了一个关键字“defer”。这个关键字允许我们指定一个代码块,即函数中的一个段,它将在程序控制权被转移到作用域之外之前执行。可能是为了清理或其他需要,即使抛出错误也需要执行的操作。

defer块中的代码执行被延迟到倒数第二条语句执行完毕,假设最后一条语句是return语句。

以下是您可以使用它的方法:

func anyFunction(someParameter: Int) -> Int {

    // Some code

    defer {

        // Code to be deferred.

    }

    return someValue

} // anyFunction

defer块的位置应该放在大括号内的任何位置,并且总是放在return语句之前,这是出于逻辑原因,也是为了避免出现警告:“永远不会执行'return'之后的代码”。

以下是一些例子:

j0pj023g

j0pj023g2#

你的问题的答案是否定的。但你的问题的解决方案很简单。

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 */) {
        DispatchQueue.main.async {
            print("about to process textField, timestamp: \(Date().timeIntervalSince1970)")
            self.process(textField)
        }
        print("about to return true, timestamp: \(Date().timeIntervalSince1970)")
        return true
    }
    else {
        return false
    }
}

DispatchQueue.main.async会将执行延迟到run循环的下一次迭代。使用这些print()语句,您会在控制台中看到这一点。您的时间戳会有所不同,但您会看到微小的差异(在本例中大约为15/1000秒)。
即将返回真,时间戳:1612578965.103658
即将处理textField,时间戳:1612578965.1188931
如果需要特定的延迟,请使用DispatchQueue.main.asyncAfter
我发现最好的解释是Matt Neuburg的书“iOS 14编程基础与Swift”。

ao218c7q

ao218c7q3#

我认为您需要将流程代码移到另一个函数中。

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    print("view loaded")
    textField.addTarget(self,
        action: "textFieldDidChange:", forControlEvents: .EditingChanged)
}

func textFieldDidChange(textField: UITextField){
    print("text changed: \(theTextField.text)")
    self.process(textField)
}
8gsdolmq

8gsdolmq4#

在return语句之后没有语言原语来运行任意代码。没有语言提供这一点。然而,你总是可以使用闭包来嵌入和排序代码流;就像完成处理程序一样。
在某些情况下,您可能需要使用willSet和/或didSet。假设有一个String属性作为文本字段的后备存储。如果字符串通过验证,则您写入后备存储。这将触发willSet,它可以运行您的process代码,并根据结果直接更新textField

0h4hbjxa

0h4hbjxa5#

延迟注入应该在代码的可达语句处,否则它们将不会在代码块的末尾执行。基本上,这是延迟的主要思想。

cld4siwp

cld4siwp6#

一旦函数返回,函数的被调用生命周期就结束了。为了保证函数返回后的第一次执行,需要调用函数的对象在序列化环境中执行该函数。
然而,在您的用例中,该函数是由用户输入调用的,除非我们对此进行子类化或混合处理,否则我建议在您的用例中使用具有不明显延迟的异步调度:

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)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            // async allows control to fall through
            // delay ensures call after return
        }
        return true
    }
    else {
        return false
    }
}

这是一个边缘黑客,我个人不喜欢这种解决方案,但替代方案是如此丑陋,从用户端,它会看起来无缝。肯定有启发式的工程空间,这是一个这样的情况。

相关问题