How can I pass a function pointer in Swift?

I would like to take this sample code

override func viewDidLoad() {
  super.viewDidLoad()

  let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
  button.backgroundColor = .greenColor()
  button.setTitle("Test Button", forState: .Normal)
  button.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)

  self.view.addSubview(button)
}

func buttonAction(sender: UIButton!) {
  print("Button tapped")
}

...and place the code to create the button in another file. So it would look more like this:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        makeButton(vControl: self)
    }

    @objc func buttonAction(sender: UIButton!) {
      print("Button tapped")
    }
    
}

Of course the main flaw is that I would have to pass a pointer to the function buttonAction.

Something like we do in C

makeButton(vControl: self, bFunc: &buttonAction)

Have Googled a lot but can't seem to find the way to do this. How do I set up the makeButton page to recieve this?

func makeButton (vControl: ViewController, bFunc: ???)

What would the ??? be in reality?

thanks

Answered by OOPer in 691508022

I would have to pass a pointer to the function buttonAction

Seems you may be mistaking something. In target-action pattern of UIKit, you need to pass a pair of target and action. And the action is not a function pointer, but is a selector.

So, you can write something like this:

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        makeButton(vControl: self, action: #selector(self.buttonAction(sender:)))
    }
    
    @objc func buttonAction(sender: UIButton!) {
        print("Button tapped")
    }
    
}

func makeButton(vControl: ViewController, action: Selector) {
    let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
    button.backgroundColor = .green
    button.setTitle("Test Button", for: .normal)
    button.addTarget(vControl, action: action, for: .touchUpInside)
    
    vControl.view.addSubview(button)
}
Accepted Answer

I would have to pass a pointer to the function buttonAction

Seems you may be mistaking something. In target-action pattern of UIKit, you need to pass a pair of target and action. And the action is not a function pointer, but is a selector.

So, you can write something like this:

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        makeButton(vControl: self, action: #selector(self.buttonAction(sender:)))
    }
    
    @objc func buttonAction(sender: UIButton!) {
        print("Button tapped")
    }
    
}

func makeButton(vControl: ViewController, action: Selector) {
    let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
    button.backgroundColor = .green
    button.setTitle("Test Button", for: .normal)
    button.addTarget(vControl, action: action, for: .touchUpInside)
    
    vControl.view.addSubview(button)
}

Thanks for the answer, I will have to study up on Selectors, hate all this different terminology. For instance the syntax:

action: action, for: .touchUpInside

makes no sense to me. To me, it's still a call back. Will still have to find out how to pass a pointer to a function at some point I guess.

Will mark you answer correct, just want to make sure you see this comment

p.s. Also confused since the sample code that worked, without having the second action with the comma:

An example, which I think it illustrates how Selector is different than a function pointer:

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        makeButton(vControl: self, action: #selector(AnotherClass.buttonActionWithSender(_:))) //<-
    }
    
    @objc func buttonAction(sender: UIButton!) {
        print("Button tapped")
    }
    
}

func makeButton(vControl: ViewController, action aSelector: Selector) {
    let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
    button.backgroundColor = .green
    button.setTitle("Test Button", for: .normal)
    button.addTarget(vControl, action: aSelector, for: .touchUpInside)
    
    vControl.view.addSubview(button)
}


class AnotherClass: NSObject {
    @objc func buttonActionWithSender(_ sender: UIButton) {
        print("\(type(of: self))-\(#function)")
    }
}

Please see what will happen with this code.

How can I pass a function pointer in Swift?
 
 
Q