J. Doe
J. Doe

Reputation: 13

Setting the state of a UiButton from a function in Swift

I have 7 Buttons to toggle the days in a week on and off. If, for example, the button for Sunday is pressed, an IBAction toggles the state automatically without any problems:

@IBAction func SoToggle(_ sender: UIButton) {
    self.So.isSelected = !self.So.isSelected;
}

But when I try to set the state of that button from a function in the same class, I get an error saying:

unexpectedly found nil while unwrapping an Optional value

Here is the code used for setting "isSelected" to either true or false:

func setSo(state: Bool) {
    self.So.isSelected = state
}

I don't get why this is not working, because it's pretty much the same code.

EDIT: The function is called by the TableViewController and the buttons are located in a custom TableViewCell. I included the whole code, just to make things clear. TableViewController:

class TableViewSettings: UITableViewController{

let sections = ["weekdays", "start time"]

var CellDays:TableViewCellDays = TableViewCellDays()
override func viewDidLoad() {
    super.viewDidLoad()

    self.view.layer.cornerRadius = 7

    self.tableView.contentInset = UIEdgeInsets(top: 10,left: 0,bottom: 0,right: 0)

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

// MARK: - Table view data source

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return self.sections[section]
}

override func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return sections.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return 1
}


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if(indexPath.section == 0) {
        return Bundle.main.loadNibNamed("TableViewCellDays", owner: self, options: nil)?.first as! TableViewCellDays
    } else {
        return Bundle.main.loadNibNamed("TableViewCellPicker", owner: self, options: nil)?.first as! TableViewCellPicker
    }
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if(indexPath.section == 0) {
        return 80
    } else {
        return 150
    }
}


override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return 15
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 30
}

override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
    let v: UIView = UIView()
    v.backgroundColor = .clear
    return v;
}

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let cell = Bundle.main.loadNibNamed("TableViewCellHeader", owner: self, options: nil)?.first as! TableViewCellHeader

    cell.mainLabel.text = sections[section]

    return cell
}

func setSettingsButtons(settings: [String]) {
//        if (settings[0] == "1") {
//            CellDays.Mo.isSelected = true
//        } else {CellDays.Mo.isSelected = false}
//        
//        if (settings[1] == "1") {
//            CellDays.Di.isSelected = true
//        } else {CellDays.Di.isSelected = false}
//        
//        if (settings[2] == "1") {
//            CellDays.Mi.isSelected = true
//        } else {CellDays.Mi.isSelected = false}
//        
//        if (settings[3] == "1") {
//            CellDays.Do.isSelected = true
//        } else {CellDays.Do.isSelected = false}
//        
//        if (settings[4] == "1") {
//            CellDays.Fr.isSelected = true
//        } else {CellDays.Fr.isSelected = false}
//        
//        if (settings[5] == "1") {
//            CellDays.Sa.isSelected = true
//        } else {CellDays.Sa.isSelected = false}
//        
//        if (settings[6] == "1") {
//            CellDays.So.isSelected = true
//        } else {CellDays.So.isSelected = false}

    CellDays.setSo(state: true)
}

TableViewCell:

class TableViewCellDays: UITableViewCell {

@IBOutlet var Mo: UIButton!
@IBOutlet var Di: UIButton!
@IBOutlet var Mi: UIButton!
@IBOutlet var Do: UIButton!
@IBOutlet var Fr: UIButton!
@IBOutlet var Sa: UIButton!
@IBOutlet var So: UIButton!

@IBOutlet var MoLeading: NSLayoutConstraint!
@IBOutlet var DiLeading: NSLayoutConstraint!
@IBOutlet var MiLeading: NSLayoutConstraint!
@IBOutlet var DoLeading: NSLayoutConstraint!
@IBOutlet var FrLeading: NSLayoutConstraint!
@IBOutlet var SaLeading: NSLayoutConstraint!
@IBOutlet var SoLeading: NSLayoutConstraint!



var offset: CGFloat = 10

override func awakeFromNib() {
    super.awakeFromNib()

    // init Button states

    Mo.isSelected = false
    Di.isSelected = false
    Mi.isSelected = false
    Do.isSelected = false
    Fr.isSelected = false
    Sa.isSelected = false
    So.isSelected = false


    let screenWidth = UIScreen.main.bounds.width
    let screenWidthCenter = screenWidth/2
    let frameWidth = Do.frame.width

    // Offset Settings depending on Device

    offset = screenWidth / 37

    print(offset)


    // X Coordinate Settings

    MoLeading.constant = screenWidthCenter - 3.5 * frameWidth - 3.75 * offset
    DiLeading.constant = screenWidthCenter - 2.5 * frameWidth - 2.75 * offset
    MiLeading.constant = screenWidthCenter - 1.5 * frameWidth - 1.75 * offset
    DoLeading.constant = screenWidthCenter - 0.5 * frameWidth - 0.75 * offset
    FrLeading.constant = screenWidthCenter + 0.5 * frameWidth + 0.25 * offset
    SaLeading.constant = screenWidthCenter + 1.5 * frameWidth + 1.25 * offset
    SoLeading.constant = screenWidthCenter + 2.5 * frameWidth + 2.25 * offset



}

@IBAction func MoToggle(_ sender: UIButton) {
    self.Mo.isSelected = !self.Mo.isSelected;
}

@IBAction func DiToggle(_ sender: UIButton) {
    self.Di.isSelected = !self.Di.isSelected;
}

@IBAction func MiToggle(_ sender: UIButton) {
    self.Mi.isSelected = !self.Mi.isSelected;
}

@IBAction func DoToggle(_ sender: UIButton) {
    self.Do.isSelected = !self.Do.isSelected;
}

@IBAction func FrToggle(_ sender: UIButton) {
    self.Fr.isSelected = !self.Fr.isSelected;
}

@IBAction func SaToggle(_ sender: UIButton) {
    self.Sa.isSelected = !self.Sa.isSelected;
}

@IBAction func SoToggle(_ sender: UIButton) {
    self.So.isSelected = !self.So.isSelected;
}

func setSo(state: Bool) {
    self.Mo.isSelected = state
}

}

Upvotes: 1

Views: 756

Answers (1)

Juri Noga
Juri Noga

Reputation: 4391

First you have to register the nib for table view to be able to use it.

Add in viewDidLoad:

self.tableView.register(UINib(nibName:"TableViewCellDays", bundle:nil), forCellReuseIdentifier: "TableViewCellDays")

Replace your variable declaration as follows:

var CellDays:TableViewCellDays?

You will assign a value to it later in datasource methods.

Next in your tableView: UITableView, cellForRowAt get this cell and assign the instance variable CellDays to it:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   if(indexPath.section == 0) {
        let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCellDays") as! TableViewCellDays
        self.CellDays = cell
        return cell
   } else {
        return Bundle.main.loadNibNamed("TableViewCellPicker", owner: self, options: nil)?.first as! TableViewCellPicker
   }
}

Only after that you can call your setSettingsButtons method.

Upvotes: 0

Related Questions