Lawrence413
Lawrence413

Reputation: 2016

Execute code when pressing button created programmatically in function

I have created a custom Alert View with buttons that are created dynamically.

Everything works fine except I don't know how to make each button do something different.

What I mean by that is that I call a function addButton and I pass a block of code (like in UIAlertAction()). I want that code to execute after I press the button but it actually gets executed when the button is loaded.

Sorry if I'm unclear but I don't know the specific terms about my issue. Basically I tried to reproduce UIAlertView and I don't know how to fully remake UIAlertAction.

Here's the method (note: it's in a custom class):

func addButton(buttonNumber number: Int, title: String, color: UIColor, actions: () -> Void ) {
    // Initialization
    let button = UIButton(frame: CGRectMake(5, self.wrapper.bounds.height-CGFloat(55*number), self.wrapper.bounds.width-10, 50))
    // Configuration
    button.setTitle(title, forState: .Normal)
    button.backgroundColor = color
    button.layer.cornerRadius = 10
    button.addTarget(self, action: #selector(myCustomView.buttonPressed(actions:)), forControlEvents: .TouchUpInside)

    wrapper.addSubview(button)
}

This is the selector (I know it's not correct):

func buttonPressed(actions actions: () -> Void) {
    actions() // How do I get the actions from addButton?
}

And this is when I call addButton:

        let alertView = UIStoryboard(name: "Popups", bundle: nil).instantiateViewControllerWithIdentifier("HAlertView") as! HAlertViewVC
        prepareAlert(alertView)

        alertView.loadAlert(title: "Hold on", message: "You need to add at least the goal before saving", image: "Warning-Icon", numberOfActions: 1)

        alertView.addButton(buttonNumber: 1, title: "Close", color: UIColor(red: 246.0/255.0, green: 71.0/255.0, blue: 71.0/255.0, alpha: 1), actions: { 
    //        alertView.dismiss() // This is the problem. That's just a function that hides the alert view but the issue is that it gets executed right away.
        })

Upvotes: 1

Views: 529

Answers (1)

Fluidity
Fluidity

Reputation: 3995

What you are looking for are closures:

  var some_code_block = {
      print("my awesome code block!")
  }

Put this at a higher / global scope, then you can run / change the block at will, simply by adding '()' at the end of the closure (variable name)

 func addCode() {
     // Wont execute:
     some_code_block = { print("new code inserted") }
 }

 func buttonPressed() {
     // Executes: 
     some_code_block()
 }

Personally, I use arrays / dictionaries to store / update code blocks on the fly.. then you can iterate through / match indices/keys to get the code block you want.

https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html

If your problem is actually making different buttons, then you can store your newly created instance of a UI button into an array or dictionary

[UIButton]

An array / dictionary of buttons, matching with an array / dictionary of code blocks can certainly work... You just have to make sure they are in the right scope / and synchronize indices / keys.

Or, you could create a class / struct that holds a UIButton instance, and a code block, then put the class / struct into an array / dictionary

// Make your own initializer for your purposes
struct ButtonStuff {
    var button: UIButton?
    var code_block: ()?
}

// Make empty array that holds type ButtonStuff (global / outer scope)
var buttons: [ButtonStuff] = [] 

func addButton(pram1:Pram1, pram2:Pram2) {
    // Make a new button (called locally inside of a func)
    var new_button = ButtonStuff()

    // Put stuff in here...
    // new_button.button = pram1
    // new_button.code_block = pram2

    // Add our locally made new_button to the Global buttons array
    buttons.append(new_buttons)
}

NOTE: The pram1, pram2 can be whatever you want, but to store to the code block (without running it) you want type (). If you want to automatically run the code block, you would use type ()->()

There are many ways of doing the above (you don't have to use optionals); just a quick example. You would then just have to make some logic / algo to find the right button, display it, then call the code block.

If you have any questions, need me to edit my answer, please leave a message in the comments with @fluidity

Upvotes: 1

Related Questions