【问题标题】:How can I run code after the return statement in a function in Swift?如何在 Swift 函数中的 return 语句之后运行代码?
【发布时间】:2016-03-20 17:33:24
【问题描述】:

考虑以下代码:

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 的含义,但是还有其他选择吗?比如,有没有办法从函数中返回一个值,然后继续运行?

一方面,这似乎是一个愚蠢的问题,但另一方面,我觉得我不可能成为第一个想要这样做的人。如果我可以在运行循环的下一个循环中触发一些东西来运行就足够了,所以也许 GCD 中有一些东西可以帮助我。

【问题讨论】:

  • Google for Grand Central Dispatch

标签: swift swift2 return


【解决方案1】:

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

defer 块内的代码执行会延迟到执行倒数第二条语句,假设最后一条语句是返回语句。

你可以这样使用它:

func anyFunction(someParameter: Int) -> Int {

    // Some code

    defer {

        // Code to be deferred.

    }

    return someValue

} // anyFunction

出于逻辑原因并避免警告:“代码'return' 之后将永远不会被执行”。

一些例子:

【讨论】:

  • 请勿参考此答案:在 return 语句之后没有执行任何操作。查看代码的结果:ibb.co/kb4Hg9。它给出了编译时警告。对帖子的回答:只需将defer{} 视为函数的析构函数。就是这样,它会在函数即将超出其范围时执行。
  • @YashBedi 感谢您的澄清,我已经更新了答案。
  • @YashBedi 您应该阅读帮助中心的“否决”页面:“不要投反对票:如果有问题,请发表评论或编辑帖子以进行更正。”来源:stackoverflow.com/help/privileges/vote-down
  • 你现在快乐。
【解决方案2】:

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

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)
}

【讨论】:

    【解决方案3】:

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

    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 会将执行推迟到运行循环的下一次迭代。使用这些 print() 语句,您将在控制台中看到这一点。您的时间戳会有所不同,但您会看到微小的差异(在本例中约为 15/1000 秒)。

    即将返回true,时间戳:1612578965.103658

    即将处理textField,时间戳:1612578965.1188931

    如果您需要特定的延迟,请使用 DispatchQueue.main.asyncAfter

    我找到的最好的解释是 Matt Neuburg 的书“iOS 14 Programming Fundamentals with Swift”。请参阅延迟性能部分。

    【讨论】:

      【解决方案4】:

      没有语言原语可以在 return 语句之后运行任意代码。没有语言提供这一点。但是,您始终可以使用闭包来嵌入和排序代码流;就像一个完成处理程序。

      在某些情况下,您可能想要使用willSet 和/或didSet。想象一下,有一个 String 属性作为文本字段的后备存储。如果字符串被验证,那么你写入后备存储。这将触发willSet,它可以运行您的process 代码并根据结果直接更新textField。

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          一旦函数返回,这就是该函数生命的终结。为了保证在函数返回后首先执行某事,需要调用该函数的对象在序列化环境中执行该某事。

          但是,在您的用例中,该函数是由用户输入调用的,除非我们通过子类化或调配我们的方式,否则我在您的用例中建议采用不明显延迟的异步调度:

          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
              }
          }
          

          这是一个边缘黑客,我个人不喜欢这种解决方案,但替代方案更丑陋,从用户端来看,它看起来是无缝的。启发式算法在工程中肯定有空间,这就是其中之一。

          【讨论】:

            猜你喜欢
            • 2022-09-24
            • 2023-02-07
            • 1970-01-01
            • 2011-09-22
            • 2012-02-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-11-17
            相关资源
            最近更新 更多