Enabling one UIButton when another UIButton is pressed

This is getting frustrating! Making one UIButton enable another button and change its state to .isHidden to false should be relatively simple. I have been wrestling with this dilemma for way too long and need some help.


class Buttons: Numbers {
    
    var button = UIButton()
    
    func unhideBtn (sender: Any?)
    {
        
        button.isHidden = false
        button.isEnabled = true
    }
    
    /* generate button sends data to labels
     and should enable buttons 1 - 5
     
     */
    
    
    @IBAction func save(_ sender: UIButton) {
        button = sender.self
        
        savedNumbers.arrayStuff()
        print("just left the saveButton")
    }
    
    
    @IBAction func generateButton(_ sender: UIButton)
    {
        button.isHidden = false
        purge()
        if (buttonPressed == false) { errorMsg(tag: sender.tag) }
        else { sortBallNumbers(lottoArray: lotto, bonusArray: bonus) }
    }
   


I have tried numerous versions of buttonName.isHidden and buttonName.isEnabled but alas no joy. Everthing I have researched all recommend to "simply" use the button's name. But when I try to use the "save" button and set it to .isHidden or .isEnabled but I get errors like:

Value of type '(UIButton) -> ()' has no member 'button' for

saveNumbers.editButtonItem = editButtonItem.isEnabled


Value of tuple type '()' has no member 'isHidden'

let button = saveNumbers(<sender: UIButton)
        button.isHidden = false


This can't be this difficult can it?

Accepted Reply

I do understand that creating var button = Button() creates an instance but I was getting desparate

var button = UIButton() // <---- var for saveNumbers button (nothing else worked

When you create a button that way, it is not connected to the button in IB.

So you need to create the button in the view, and define its title, target and IBAction ; you usually do it in viewDidLoad (and no need to declare a var for the button, it is created and added as a subview, unless you need to access its properties later.


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


You then define the buttonAction:

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


It seems you cannot make it by defining the button in IB :

However, when I do it doesn't give the option of outlet or action just exit

Make sure that the class defined in IB matches the one defined in the code of viewController.


So by making the button an outlet versus an action gives the button more accessability?


Partly true, but the 2 are not alternatives, they are very different things :

- you create an IBAction to have it executed when you hit the button.

That may be enough, unless

- you want to change some button's property (like title, hide / unhide, activate / deactivate…) : then you need to access to the object instance by code: that is the role of the IBOutlet.

Replies

Please show enough code to explain and reproduce your issue?


What is `Numbers`, `savedNumbers.arrayStuff`, `purge`, `buttonPressed` and `sortBallNumbers(lottoArray:bonusArray:)`...?


How are you using your `Buttons` class? How have you connected `save(_:)` or `generateButton(_:)`?

Why are you showing `unhideBtn(_:)` which is not used from other parts shown?


How many and what sort of buttons do you have and how do you want them to work?


I think you are making things too more complex than it should be, but it is very hard to explain how you can simplify, without such info above.


Please describe what you really want to do more clearly.

import Foundation
import UIKit

class Buttons: UIViewController {
    
    var button = UIButton()  //    <---- var for saveNumbers button (nothing else worked
                             //             oddly this didn't either)
    var numbers = Numbers() //  <---- instance fromthe Numbers class to connect to arrays
    
    var getTag: Int = 0        //  <---- var used to get senders tag to send to errorMsg() 
                              //         and a switch in Numbers
    var buttonPressed = false  //  <---- Bool to use in errorMsg()
    
    func errorMsg(tag: Int)
    {
        
        if (buttonPressed != true && getTag != 10) {
            let errorAlert = UIAlertController(title: "Error", message: "You must select a game before using this feature", preferredStyle: .alert)
            
            let checkOut = UIAlertAction(title: "OK", style: .default, handler: nil)
            errorAlert.addAction(checkOut)
            present(errorAlert, animated: true, completion: nil)
            
        } else { }
    }  /* ******** end of errorMsg method *************** */
    
    
    
    func catchError ()
    {
        let alertError = UIAlertController(title: "ERROR", message: "Something went wrong", preferredStyle: .alert)
        
        let getOut = UIAlertAction(title: "OOPS", style: .default, handler: nil)
        
        alertError.addAction(getOut)
        present(alertError, animated: true, completion: nil)
    }  /* ******** end of catchError method *************** */
    
    
    func unhideBtn (sender: Any?)  // <----- thought it would be better to try a func to call from
    {                              //        generateButton
        
        button.isHidden = false
        button.isEnabled = true
    }
    
   
    
    func purge()     // <---- resets the temporary arrays for reuse when other buttons are pressed
    {
        numbers.bonusSort.removeAll()
        numbers.lottoSortAscend.removeAll()
        numbers.lottoSortDescend.removeAll()
    }  /* ******** end of purge method *************** */
    
    
    @IBAction func saveNumbers(_ sender: UIButton) {
        let savedNumbers = SavedNumbers()
        savedNumbers.arrayStuff()        // <---- builds an array for a tableview in
        print("just left the saveButton")//       SavedNumbers class
    }
    
    
    @IBAction func generateButton(_ sender: UIButton)
    {
        
        unhideBtn(sender: self.saveNumbers)
        purge()
        if (buttonPressed == false) { errorMsg(tag: sender.tag) }
        else { numbers.sortBallNumbers(lottoArray: lotto, bonusArray: bonus) }
    }
    
    @IBAction func highLow(_ sender: UIButton)
    {
        errorMsg(tag: sender.tag)
        getTag = sender.tag
    }
    @IBAction func highHigh(_ sender: UIButton)
    {
        errorMsg(tag: sender.tag)
        getTag = sender.tag
    }
    @IBAction func lowLow(_ sender: UIButton)
    {
        errorMsg(tag: sender.tag)
        getTag = sender.tag
    }
    @IBAction func lowHigh(_ sender: UIButton)
    {
        errorMsg(tag: sender.tag)
        getTag = sender.tag
    }
    @IBAction func random(_ sender: UIButton)
    {
        errorMsg(tag: sender.tag)
        getTag = sender.tag
    }
    
    @IBAction func powerball(_ sender: UIButton)
    {
        purge()
        JsonData().getJSONAndParse(gameToParse: "Powerball")
        buttonPressed = true
        editButtonItem.isEnabled = !editButtonItem.isEnabled
    }
    
    @IBAction func megamillions(_ sender: UIButton)
    {
        purge()
        JsonData().getJSONAndParse(gameToParse: "Megamillions")
        buttonPressed = true
    }
    
    
    
    
} /* ************ end of Numbers class ****************** */

I know it's not up to par with other questions I see on here, but I figured it's the best place to get answers.

When you write “var button = UIButton()”, you’re creating a brand new instance. Unless you’re adding that to the view hierarchy yourself somewhere, that button is not on screen. Setting it hidden or not has no effect. I suspect you want to create an IBOutlet instead. CTRL-drag from the button on the storyboard into your code to make an outlet. Then that button IBOutlet var refers to an actual button that UIKit has created for you from the storyboard.

Thank you for your reply! I have tried to Ctrl+Drag the button from the storyboard to the code and also from the Document Outline.

However, when I do it doesn't give the option of outlet or action just exit. I assume it's because i am dragging to a different class/storyboard. I do understand that creating var button = Button() creates an instance but I was getting desparate 😟 I tend to try different things until the errors become warnings or just go away...I know it is not the best programming technique but it truly has helped me learn.


I have read the API documentation and did some research online but I really couldn't find what I was looking for. Well maybe I did but I didn't understand it.


So by making the button an outlet versus an action gives the button more accessability?


Again thank you very much for helping me!

I do understand that creating var button = Button() creates an instance but I was getting desparate

var button = UIButton() // <---- var for saveNumbers button (nothing else worked

When you create a button that way, it is not connected to the button in IB.

So you need to create the button in the view, and define its title, target and IBAction ; you usually do it in viewDidLoad (and no need to declare a var for the button, it is created and added as a subview, unless you need to access its properties later.


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


You then define the buttonAction:

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


It seems you cannot make it by defining the button in IB :

However, when I do it doesn't give the option of outlet or action just exit

Make sure that the class defined in IB matches the one defined in the code of viewController.


So by making the button an outlet versus an action gives the button more accessability?


Partly true, but the 2 are not alternatives, they are very different things :

- you create an IBAction to have it executed when you hit the button.

That may be enough, unless

- you want to change some button's property (like title, hide / unhide, activate / deactivate…) : then you need to access to the object instance by code: that is the role of the IBOutlet.

Brilliant! That is an awesome explanation and helped me greatly. I have a much better understanding of the difference between action and outlet. The .addTarget example helped me tremendously, I was having comprehension fits with it, but now its clear.


Thanks again, I'm excited to ask more questions 🙂