Button as a variable - swift

I am trying to have a variable set to a buttons label.
I have something like this:
#IBOutlet weak var myButton: UIButton!
var myVariable = String()
#IBAction func ButtonPressed(_ sender: Any) {
myVariable = myButton.titleLabel
}
Can anyone tell my how I can make this work?

titleLabel is an instance of UILabel. Your myVariable is a String property. That does not match typewise. You can access titleLabel directly, as in:
myVariable = myButton.titleLabel?.text ?? ""
But UIButton class defines a title(for:) method to access title of the button for various states.
Thus, in your case I would recommend using following:
#IBOutlet weak var myButton: UIButton!
var myVariable = String()
#IBAction func ButtonPressed(_ sender: Any) {
myVariable = myButton.title(for: .normal) ?? ""
}

You're nearly there, you're just missing the text property. Also you might want to set your variable as an optional.
#IBOutlet weak var myButton: UIButton!
var myVariable: String?
#IBAction func ButtonPressed(_ sender: Any) {
myVariable = myButton.titleLabel?.text
}

Related

Swift Combine question with UILabel subscribe

import UIKit
import Combine
class ViewController: UIViewController {
#IBOutlet weak var allowMessageSwitch: UISwitch!
#IBOutlet weak var sendButton: UIButton!
#IBOutlet weak var messageLabel: UILabel!
#Published var canSendMessages: Bool = false
#Published var newMsg: String = ""
private var switchSubscriber: AnyCancellable?
private var btnSubscriber: AnyCancellable?
override func viewDidLoad() {
allowMessageSwitch.isOn = false
super.viewDidLoad()
setupProcesscingChain()
}
func setupProcesscingChain() {
switchSubscriber = $canSendMessages.receive(on: DispatchQueue.main).assign(to: \.isEnabled, on: sendButton)
btnSubscriber = $newMsg.receive(on: DispatchQueue.main).assign(to: \.text, on: messageLabel)
}
#IBAction func didSwitch (_ sender: UISwitch) {
canSendMessages = sender.isOn
}
#IBAction func sendMessage( _ sender: Any) {
}
}
I am getting error in
btnSubscriber = $newMsg.receive(on: DispatchQueue.main).assign(to: \.text, on: messageLabel)
error msg is
Type of expression is ambiguous without more context
I dont understand why label does not work as Switcher (bool)
I assume it is because \.isEnabled is not optional, and \.text is optional..??
how can I make this work with the same format. this is for practice and to understand how Combine works.. please help!
lableSubscriber = $newMsg.receive(on: DispatchQueue.main).assign(to: \.text!, on: messageLabel)
I solved it on my own! it was very simple.
just force unwrap the keyPath.

How to allow dot or comma in UITextField in calculation?

I am newbie in coding. I just started to learn #swift and trying yo make a calculation app. My problem is my UITextField doesn't work with dot or comma.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var ilkLabel: UITextField!
#IBOutlet weak var ikinciLabel: UITextField!
#IBOutlet weak var sonucLabel: UILabel!
#IBOutlet weak var ilk2Label: UITextField!
#IBOutlet weak var ikinci2Label: UITextField!
#IBOutlet weak var sonuc2Label: UILabel!
#IBOutlet weak var ilk3Label: UITextField!
#IBOutlet weak var ikinci3Label: UITextField!
#IBOutlet weak var sonuc3Label: UILabel!
var sonuc:Double = 0
var sonuc2:Double = 0
var sonuc3:Double = 0
var deneme:Double = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
#IBAction func plusBtn(_ sender: Any) {
func forTrailingZero(temp: Double) -> String {
let tempVar = String(format: "%g", temp)
return tempVar
}
deneme = Double(Int(ikinciLabel.text!)! + 100 / 100 * Int(ilkLabel.text!)!)
sonucLabel.text = String(forTrailingZero(temp: Double(ikinciLabel.text!)! / 14.56 ) )
}
#IBAction func plus2Btn(_ sender: Any) {
}
#IBAction func plus3Btn(_ sender: Any) {
}
}
I expect to make calculation like 1.4 + 2.35 but when i try the app crashes. I can only calculate whole number like 2 + 2.
#matt is right. If the text in ikinciLabel is not an Int, the app crashes. You tell it to crash by using the force unwrap operator: !.
In general
You should only force-unwrap things when you are absolutely sure that the thing you want to unwrap is not nill. In all other cases you should if-let or guard-let the optional, use the nil-coalescing operator (??) (or other ways to unwrap optionals) and handle the nil-case.
In your case
if you want to allow the user to enter floating point numbers using either a comma or a dot, you could simply replace every comma with a dot like so:
let enteredTextWithoutComma = textField.text?.replacingOccurrences(of: ",", with: ".")
This new constant is an optional. To safely make a Double out of it, do:
guard let enteredTextWithoutCommaUnwraped = enteredTextWithoutComma,
let enteredNumber = Double(enteredTextWithoutCommaUnwraped) else {
// one of the two actions didn't work. Maybe the entered phrase was not a number
// do something
return
}
// here you can use the variable enteredNumber. It is now a Double (not an Optional)
...

How to update UITableView when a CustomCell label value changes?

I have a custom cell class with two buttons and one label defined in its own class. Am using protocol-delegates to update the value of the label when the button is pressed. But am not able to figure out how to update the UITableView.
protocol customCellDelegate: class {
func didTapDecrementBtn(_ sender: AllCountersTableViewCell)
func didTapIncrementBtn(_ sender: AllCountersTableViewCell)
func updateTableViewCell(_ sender: AllCountersTableViewCell)
}
class AllCountersTableViewCell: UITableViewCell {
#IBOutlet weak var counterValueLbl: UILabel!
#IBOutlet weak var counterNameLbl: UILabel!
#IBOutlet weak var counterResetDateLbl: UILabel!
#IBOutlet weak var counterDecrementBtn: UIButton!
#IBOutlet weak var counterIncrementBtn: UIButton!
weak var delegate: customCellDelegate?
#IBAction func decrementBtnPressed(_ sender: UIButton) {
delegate?.didTapDecrementBtn(self)
delegate?.updateTableViewCell(self)
}
#IBAction func incrementBtnPressed(_ sender: UIButton) {
delegate?.didTapIncrementBtn(self)
delegate?.updateTableViewCell(self)
}
In my ViewController, I have provided the delegate. But reloadData() is not working, so although sender.counterLbl.value is changing its not reflecting on the view.
extension AllCountersVC: customCellDelegate {
func didTapIncrementBtn(_ sender: AllCountersTableViewCell) {
guard let tappedCellIndexPath = tableView.indexPath(for: sender) else {return}
let rowNoOfCustomCell = tappedCellIndexPath[1]
let newValue = String(allCounter[rowNoOfCustomCell].incrementCounterValue(by: allCounter[rowNoOfCustomCell].counterIncrementValue))
sender.counterValueLbl.text = newValue
}
func updateTableViewCell(_ sender: AllCountersTableViewCell) {
allCountersTableView.reloadData()
}
In cellForRow you must set cell.delegate = self for this logic to start working. Its not enough just to make you controller confroms to your custom cell delegate protocol. From your post I assume delegate is always nil in the cell, that is why it does not work.

Changing of text on button not permanent

I have four buttons in a single view, with texts "A", "B", "X", "Y" on them respectively. I expected to see the texts of btnA and btnB change respectively when I pressed on btnX and btnY respectively and then both of btnA and btnB turn green. Instead, when I pressed btnA, "A" changed to "1" and immediately changed back to "A" again. But btnB changed to "2" permanently as expected.
This problem may seem simple but I just can't get the expected result. I just started to learn Swift. Please help me. Thank you!
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var btnA: UIButton!
#IBOutlet weak var btnB: UIButton!
#IBOutlet weak var btnX: UIButton!
#IBOutlet weak var btnY: UIButton!
#IBAction func btnXPressed(_ sender: UIButton) {
btnA.titleLabel?.text = "1"
check()
}
#IBAction func btnYPressed(_ sender: UIButton) {
btnB.titleLabel?.text = "2"
check()
}
func check() {
if ((btnA.titleLabel?.text)! == "1") && ((btnB.titleLabel?.text)! == "2") {
btnA.backgroundColor = UIColor.green
btnB.backgroundColor = UIColor.green
}
}
}

Nesting buttons in Swift

How can a button press another button. I want to know how to press button2 and have button1 complete its task and relay that information to button2. I feel like this answer is super simple, and any help would be greatly appreciated.
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
#IBAction func button1(sender: AnyObject) {
var textAgeArray = ["1", "2", "3"]
let randomTextAge = Int(arc4random_uniform(UInt32(textAgeArray.count)))
let displayAge = textAgeArray[randomTextAge]
textField1.text = displayAge
}
#IBAction func button2(sender: AnyObject) {
textField2.text = displayAge
}
You are using these buttons to update particular text field when a button is pressed, so put that task inside a function and then call that function from any button. If you want to track that then add a variable to check what is current text. What you are trying to do can be done through this way because you don't want to press button you want to do particular task.
As Mukesh suggested you can refactor your code, with a separate method of the repeated code.
Just thought I'd post an alternative solution. You can call the button1 method from inside of button2:
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
var displayAge: String?
#IBAction func button1(sender: AnyObject) {
var textAgeArray = ["1", "2", "3"]
let randomTextAge = Int(arc4random_uniform(UInt32(textAgeArray.count)))
displayAge = textAgeArray[randomTextAge]
textField1.text = displayAge
}
#IBAction func button2(sender: AnyObject) {
button1(sender)
textField2.text = displayAge
}
Note that you must take the displayAge variable out so that the button2 method can access it. This will make textField1 and textField2's text the same. I'm not sure if that's the desired result as I can't tell from your post. If you want these to be different random fields then I would suggest you refactor it to have the repeated method separate.
This will also set both of the text fields at the same time. If you don't want to refactor your code to only set one field at a time then you could start tagging your button's to see where the call is coming from:
#IBOutlet var button1: UIButton!
#IBAction func button1(sender: AnyObject) {
var textAgeArray = ["1", "2", "3"]
let randomTextAge = Int(arc4random_uniform(UInt32(textAgeArray.count)))
displayAge = textAgeArray[randomTextAge]
// if sender is this button, then update text, otherwise don't do anything
if sender.tag == 1 {
textField1.text = displayAge
}
}
By default tags are 0, but you can change them by set them like so: (You can put this in viewDidLoad)
button1.tag = 1
May as well add the solution by refactoring for completeness:
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
#IBAction func button1(sender: AnyObject) {
let displayAge = randomTextAge()
textField1.text = displayAge
}
#IBAction func button2(sender: AnyObject) {
let displayAge = randomTextAge()
// Uncomment the line below if you want to update textField1 with the same value
// textField1.text = displayAge
textField2.text = displayAge
}
func randomTextAge() -> String {
var textAgeArray = ["1", "2", "3"]
let randomTextAge = Int(arc4random_uniform(UInt32(textAgeArray.count)))
let displayAge = textAgeArray[randomTextAge]
return displayAge
}