【问题标题】:Programmatic UIButton action not being called未调用编程 UIButton 操作
【发布时间】:2018-08-24 09:50:36
【问题描述】:

我创建了一个类,该类将创建/管理多个按钮和标签,并将它们添加到视图中,但我无法从按钮中获取要触发的操作。

这是一个没有“MakerClass”但运行良好的简单代码版本(代码在主 ViewController 中):

@objc func pressed(_ sender: UIButton!) {
    print("pressed")
}
    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.


    let backgroundButton = UIButton()
    backgroundButton.backgroundColor = UIColor.green
    backgroundButton.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
    self.view.addSubview(backgroundButton)

    backgroundButton.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside)

}

这是一个版本,我将按钮的创建放入不同的类中

视图控制器

    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.


    MakerClass(intoView: self.view)                
}

MakerClass

class MakerClass {


    var backgroundButton: UIButton = UIButton()


    @objc func iwastouched(_ sender: UIButton!) {
        print("touched")
    }

    init(intoView: UIView){

        backgroundButton.backgroundColor = UIColor.red
        backgroundButton.frame = CGRect(x: 0, y: 200, width: 100, height: 100)
        intoView.addSubview(backgroundButton)
        backgroundButton.addTarget(self, action: #selector(iwastouched(_:)), for: .touchUpInside)

    }


}

我用来玩这个的项目可以从here下载

由于我是 iOS 编程新手,所以我可能会走错路

【问题讨论】:

    标签: ios swift uibutton


    【解决方案1】:

    问题是因为你没有保留MakerClass,所以按钮的目标设置为NSNull()

    您可以通过添加...来查看这一点

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    
        let buttons = view.subviews as! [UIButton]
        for button in buttons {
    
            print(button)
            print("Target :", button.allTargets.first!)
        }
    }
    
    <UIButton: 0x7ff89fd04110; frame = (0 0; 100 100); opaque = NO; layer = <CALayer: 0x60000257bac0>>
    Target : <TestProgrammaticButton.ViewController: 0x7ff89ff08050>
    <UIButton: 0x7ff89fd05020; frame = (0 200; 100 100); opaque = NO; layer = <CALayer: 0x60000257bb40>>
    Target : <null>
    

    如果你想让按钮在你的视图控制器中触发一个动作方法,你可以这样做……

    class MakerClass {
        init(intoView: UIView, with viewController: ViewController) {
            // configure
            backgroundButton.addTarget(viewController, action: #selector(iwastouched(_:)), for: .touchUpInside)
        }
    }
    

    但这会将您的 MakerClass 与特定的 ViewController 类联系起来。

    相反,您的MakerClass 可以返回格式化按钮,然后在视图控制器中设置目标/操作。


    更新

    根据下面@RakeshaShastri 的评论,由于目标设置为NSNull(),应用程序将沿着响应链向上寻找具有正确函数签名的UIResponder(通常是UIViewUIViewController)。在您的案例中,响应者链是……

    backgroundButton -> ViewController.view -> ViewController -> UIWindow

    你也可以通过添加来测试它

    @objc func iwastouched(_ sender: UIButton!) {
        print("touched")
    }
    

    到你的ViewController 班级。

    【讨论】:

    • 谢谢!做我想做的最好的方法是什么? init(intoView: UIView, withVC: ViewController){ backgroundButton.backgroundColor = UIColor.red backgroundButton.frame = CGRect(x: 0, y: 200, width: 100, height: 100) intoView.addSubview(backgroundButton) backgroundButton.addTarget(withVC, action: #selector(ViewController.pressed(_:)), for: .touchUpInside) }
    • 这可行,但不确定这是一个很好的解决方案(请参阅我的更新答案)
    • 一个有趣的发现,我注意到如果您在ViewController 中有相同的选择器,它会被调用以获取问题中的代码。 @AshleyMills 你能解释一下为什么会这样吗?
    • 哦.. 目标对象——也就是调用动作方法的对象。如果您指定 nil,UIKit 会在响应者链中搜索响应指定操作消息并将消息传递给该对象的对象。 Ohkk... 明白了:|
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 2013-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多