简体   繁体   中英

UIButton.addTarget not working correctly. Seems to be a timing thing?

I am creating a ViewController with 2 child views. One is for navigation buttons that is on the top of my main view, and a browser window below (WKWebView)

In the main view controller's viewDidLoad function I create and add these views as subviews. I then create and add buttons to the navigationView. I programatically set the constraints of all the buttons to position them and size them manually.

-- Edit --

I noticed that when inspecting the button in the hierarchy, the target is set but the action is null.

Here is an image showing this

However, when I check the actions on a breakpoint immediately after adding the target, it does appear to be there.

This was done on a breakpoint immediately after adding the target


I am adding the target as follows

btnClose!.addTarget(self, action: #selector(onCloseClicked), for:UIControlEvents.touchUpInside)

The click event does not fire. However if I put a breakpoint after that line, and in the console I look at the actions for the button via

po btnClose!.allTargets

Then it shows me the target, and then when continuing execution the button works fine. I assume there's some sort of timing issue as a result but I'm not sure what the problem is.

I'm using Swift 4.1.

-- Edit --

Here is all the code involved in that button: (I removed all the webview code that isn't relevant)

public func initialize(){ // called by viewDidLoad
    navigationView = UIView(frame:navigationRect)
    navigationView!.isOpaque = true
    navigationView!.isUserInteractionEnabled = true
    navigationView!.backgroundColor = UIColor(red: 58.0/255.0, green: 60.0/255.0, blue: 67.0/255.0, alpha: 1)
    view.addSubview(navigationView!)
    addNavigationButtons()
}
private func addNavigationButtons(){
    btnClose = UIButton()
    btnClose!.addTarget(self, action: #selector(onCloseClicked), for:UIControlEvents.touchUpInside)

    btnClose!.frame = btnRect // x:0, y:0, width:50, height:50

    btnClose?.translatesAutoresizingMaskIntoConstraints = false
    btnClose!.setImage(UIImage(named: "navigationClose", in: Bundle(identifier:"myframework"), compatibleWith:nil), for:UIControlState.normal)

    navigationView!.addSubview(btnClose!)

    addButtonConstraints()
}

private func addButtonConstraints(){
    // close
    navigationView!.addConstraint(NSLayoutConstraint(item:navigationView!, attribute: .right, relatedBy: .equal, toItem: btnClose!, attribute: .right, multiplier:1.0, constant:0))
    navigationView!.addConstraint(NSLayoutConstraint(item:navigationView!, attribute: .centerY, relatedBy: .equal, toItem: btnClose!, attribute: .centerY, multiplier:1.0, constant:0))
    btnClose!.addConstraint(NSLayoutConstraint(item:btnClose!, attribute: .width, relatedBy:.equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant:MRAIDBrowserWindow.btnWidth)) //btnWidth = 50
    btnClose!.addConstraint(NSLayoutConstraint(item:btnClose!, attribute: .height, relatedBy:.equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant:MRAIDBrowserWindow.btnHeight)) //btnHeight = 50
}

@objc public func onCloseClicked(){ // tried this without @objc
    print("this doesn't work, unless I have a breakpoint stoppage")
}

First of all I should have tell you that I am not so good at setting constraints programatically, so I cannot suggest you a reasonable suggestion to that.

Here is what I have done and I am sharing the working code of your own, with a few only changes...

  1. I have added my own Image name, and backgroundColor to button to see some components might effecting the button
  2. I have removed the frame which was setting up on btnClose!, because I have noticed that you do not need to tell a frame when you are telling the container for its all sides constraints.

further more you should have a look on to it, down here is he code I have compiled to check -> your actions method calls fine

import UIKit

class MyTestActionViewController: UIViewController {

var navigationView : UIView?
var btnClose : UIButton?

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.initialize()
}

public func initialize(){ // called by viewDidLoad
    navigationView = UIView(frame:CGRect(x:5, y:55, width:200, height:200))
    navigationView!.isOpaque = true
    navigationView!.isUserInteractionEnabled = true
    navigationView!.backgroundColor = UIColor(red: 58.0/255.0, green: 60.0/255.0, blue: 67.0/255.0, alpha: 1)
    view.addSubview(navigationView!)
    addNavigationButtons()
}
private func addNavigationButtons(){
    btnClose = UIButton()
    btnClose!.addTarget(self, action: #selector(onCloseClicked), for:UIControlEvents.touchUpInside)
    
    btnClose?.backgroundColor = UIColor.red
    btnClose?.translatesAutoresizingMaskIntoConstraints = false
    btnClose?.setImage(UIImage(named: "myButtonImage"), for:UIControlState.normal)
    navigationView?.addSubview(btnClose!)
    
    addButtonConstraints()
}

private func addButtonConstraints(){
    // close
    navigationView!.addConstraint(NSLayoutConstraint(item:navigationView!, attribute: .right, relatedBy: .equal, toItem: btnClose!, attribute: .right, multiplier:1.0, constant:0))
    navigationView!.addConstraint(NSLayoutConstraint(item:navigationView!, attribute: .centerY, relatedBy: .equal, toItem: btnClose!, attribute: .centerY, multiplier:1.0, constant:0))
    btnClose!.addConstraint(NSLayoutConstraint(item:btnClose!, attribute: .width, relatedBy:.equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant:50)) //btnWidth = 50
    btnClose!.addConstraint(NSLayoutConstraint(item:btnClose!, attribute: .height, relatedBy:.equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant:50)) //btnHeight = 50
}

@objc public func onCloseClicked(){ // tried this without @objc
    print("this doesn't work, unless I have a breakpoint stoppage")
}

}

An image showing -> your button action acting properly

在此处输入图片说明

Within method addNavigationButtons , put the following the line

btnClose!.addTarget(self, action: #selector(onCloseClicked), for:UIControlEvents.touchUpInside)

after

navigationView!.addSubview(btnClose!)

I think there is a restriction with the new version of swift, if a button is not in a ui view hierarchy, and you try to add a targe-action onto it, it won't actually work. So make sure that the button is added into a ui view hierarchy first.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM