【问题标题】:How do I targeting selector with addTarget in another class如何在另一个类中使用 addTarget 定位选择器
【发布时间】:2020-09-30 11:34:38
【问题描述】:

我试图了解如何控制组件从一个类到另一个类,但这不起作用。

class VC:UIViewController {
    override func viewDidLoad() {
        let instance = Test()
        self.view.addSubView(instance.button)
    }
}

class Test:NSObject {
    var button:UIButton!

    override init() {
        button = UIButton(frame:CGRect(x:0, y:0, width:100, height:40))
        button.setTitle(("TEST", for:.normal)
        button.addTarget(self, action: #selector(tapButton(_:)), for: .touchUpInside)
    }

    @objc func tapButton(_ sender:UIButton) {
        print("TAP Button")
    }
}

当我点击按钮时,什么也没有发生!
我试着改变

button.addTarget(self, action: #selector(tapButton(_:)), for: .touchUpInside)

button.addTarget(nil, action: #selector(tapButton(_:)), for: .touchUpInside)

这不行!

如何解决这个问题? 感谢您的帮助。

【问题讨论】:

  • 你不能重定向到一个class,你需要一个实例(比如self)来把动作重定向到。

标签: swift events target


【解决方案1】:

您有 3 个问题:

  1. instance 是一个局部变量,所以它会在 viewDidLoad() 完成后立即释放。使其成为VC 的属性。该按钮只保留对该对象的弱引用,因此当它被释放时,它变为nil。在目标是nil 的情况下,UIKit 将在响应者链上搜索操作方法。由于VC 不提供tapButton 方法,因此按下按钮时不会发生任何事情。
  2. 您需要调用super.init(),以便self 可以与按钮一起使用。 self 在所有属性都初始化之前无法创建。因为initoverride,所以必须先调用super.init() 来初始化NSObject 提供的属性,然后才能在按钮中使用self
  3. 您的框架将您的按钮置于屏幕的不可访问区域。我更改了你的框架,将按钮放在 iPhone 11 的安全区域内。我还制作了按钮 .green,以便我可以看到它。
class VC: UIViewController {
    var instance = Test()          // make instance a property
    
    override func viewDidLoad() {
        // let instance = Test()   // this was a local variable that doesn't hang around
        self.view.addSubview(instance.button)
    }


}


class Test: NSObject {
    var button: UIButton!

    override init() {
        super.init()  // call this so that you can use self below
        button = UIButton(frame:CGRect(x: 100, y: 100, width: 100, height: 40))
        button.setTitle("TEST", for:.normal)
        button.backgroundColor = .green
        button.addTarget(self, action: #selector(tapButton(_:)), for: .touchUpInside)
    }

    @objc func tapButton(_ sender: UIButton) {
        print("TAP Button")
    }

    // Add deinit to see when this object is deinitialized.  When
    // instance is local to viewDidLoad() this object gets freed
    // when viewDidLoad() finishes.
    deinit {
        print("Oops, the Test object has been deinitialized")
    }
}

【讨论】:

  • 感谢您的回答,您能否解释一下使用 call super init 的目的以及能够使用 self,我认为这是一个棘手的部分
  • 有趣的是,该项目的所有问题都在于设置它,以便您可以看到一个按钮并点击它。该按钮均不可见,因此您无法点击它。我所期望的是当您点击按钮时应用程序会崩溃,因为正如您所指出的那样,Test 对象会立即被释放,因此在您可以点击按钮时目标不再存在。
  • 感谢@vacawama,它运行良好。我错过了第一期。
  • @DuncanC,按钮只有一个对对象的弱引用,当对象被释放时它变成nil。如果目标是nil,iOS 会在响应者链中向上搜索操作方法。一个有趣的尝试是向VC 添加第二个tapButton 函数,然后如果instance 是一个局部变量,它将被调用,但是当instance 存储为时,instance 中的函数将被调用一个属性。
  • @sekoyaz,哈哈,太棒了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多