xcode - 使用调试器断点在 Xcode 8.1/Swift 3.0 中调用两次委托(delegate)方法

标签 xcode delegates swift3 overriding

我对 xcode 8.1/swift 3 有疑问。我认为这可能是调试器 XCode 软件中的一个错误,但我想我会看看是否有人看到我遗漏的东西。我正在开发一个需要覆盖与 UITextField 一起使用的退格方法的 ios 应用程序。我设置了一个委托(delegate)来观察退格键被按下。该程序一直有效,直到我在覆盖的方法中设置了调试器断点(请参见下面的代码)。当我这样做时,每次按下键而不是一次,退格方法被调用两次。如果我删除断点,则代码有效。这只是一个错误还是我做错了什么?这是代码感谢您的帮助!

import UIKit

class ViewController: UIViewController, EqFieldDelegate {

override func viewDidLoad() {
    super.viewDidLoad()

    let newField = EqField()
    newField.myDelegate = self
    newField.becomeFirstResponder()
    view.addSubview(newField)
    newField.frame = CGRect(x: 50, y: 50, width: 200, height: 150)

}

func backspacePressed( ){

    print("in backspacePressed") // breakpoint added here
}

}   

这是 UITextField 的子类:
import UIKit

class EqField: UITextField {

    var myDelegate: EqFieldDelegate?

    override func deleteBackward() {
        super.deleteBackward()
        myDelegate?.backspacePressed()
    }
}

protocol EqFieldDelegate {
    func backspacePressed()
}

最佳答案

我有一个关于为什么会发生这种情况的理论。

为了说明,假设我们正在制作自己的后退按钮。它应该具有以下模仿 Apple 的行为:

  • 触地时,请调用 backspacePressed
  • 0.5 秒后,如果触摸仍处于按下状态,请调用 backspacePressed再次
  • 每 0.1 秒后,如果触摸仍然按下,请调用 backspacePressed再次

  • 以下是我将如何实现它:
  • 将此添加到您的 viewDidLoad 的末尾
    let button = UIButton(type: .system)
    button.setTitle("Tap Me", for: .normal)
    button.addTarget(self, action: #selector(ViewController.handleButtonTouched(button:)), for: .touchDown)
    button.addTarget(self, action: #selector(ViewController.handleButtonReleased(button:)), for: .touchUpInside)
    button.frame = CGRect(x: 50, y: newField.frame.maxY, width: 200, height: 150)
    view.addSubview(button)
    
  • viewDidLoad 之后添加这个
    var buttonTimer: Timer?
    
    func handleButtonTouched(button: UIButton) {
        buttonTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false, block: { [weak self] timer in
    
            print("button's been held down for a while!")
            self?.backspacePressed()
    
            self?.buttonTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { (timer) in
                print("button's still held down")
                self?.backspacePressed()
            })
    
        })
        print("button was pressed") // add a breakpoint here
        self.backspacePressed()
    }
    
    
    func handleButtonReleased(button: UIButton) {
        buttonTimer?.invalidate()
    }
    
  • (可选)注释掉您的日志,以便您的控制台与我的实验相匹配
    func backspacePressed( ){
        //print("in backspacePressed")
    } 
    

  • 如果没有断点,如果您点击并按住此按钮,您将按照我上面概述的行为打印日志:
    button was pressed
    button's been held down for a while!
    button's still held down
    button's still held down
    button's still held down
    button's still held down
    

    如果你只是点击按钮(不要按住它),你会得到
    button was pressed
    

    但是,如果您设置断点,点击按钮,并在断点命中后等待一秒钟,然后再按继续,您会得到两个日志:
    button was pressed
    button's been held down for a while!
    

    你会想,因为你没有按住按钮足够长的时间,你不会得到第二个日志。发生的情况是,即使您在断点处停止,计时器仍在计时,并且当执行返回到程序时,会在评估按钮释放之前评估计时器的结果。

    我不确定为什么事情会按这个顺序发生 - 为什么不能在计时器事件之前处理按钮释放?但是你可以看到在没有断点的正常执行中,这甚至不是先发生什么的问题 - 短按按钮将导致在计时器停止之前调用 handleButtonReleased .

    我怀疑在您的情况下,Apple 的键盘正在做类似的事情,并且您正在设置一个断点,使您的触摸保持静止,而某个地方的计时器决定是的,这确实是一个长按!尽管它真的不是。我没有解决方法,但希望这能对正在发生的事情有所启发。

    关于xcode - 使用调试器断点在 Xcode 8.1/Swift 3.0 中调用两次委托(delegate)方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40662461/

    相关文章:

    ios - ScrollView 无法工作,我被困了 7 个小时试图修复它

    xcode - 在 Xcode 中将图像集从一个 Assets 目录复制到另一个 Assets 目录

    iphone - 在运行时实现委托(delegate)?

    c# - 未完成时终止异步委托(delegate)线程

    iOS Swift 如何在我的项目中使用 Gif 文件

    ios - 使用Application Loader上载IPA时无效的启动镜像错误上传,错误ITMS-90094

    swift - 实现 "floating bubble"对象的最佳方法

    有委托(delegate)的 Swift 闭包

    swift - Swift 3 升级时出现 "Collection corresponding..."错误

    swift - Swift 3 中泛型的泛型