Missing Identifier for Radio Button when trying to identify the Sender - swift

I'm trying to identify the clicked radio button using the Interface builder identifier.
#IBAction func text_radio_changed(_ sender: Any) {
let button:NSButton = sender as! NSButton
let id:String = button.accessibilityIdentifier()
print("===========>"+id)
}
But the console keeps printing this
===========>
There is no identifier

button.accessibilityIdentifier is the Accessibility Identity Identifier. The Identity Identifier is button.identifier.
#IBAction func text_radio_changed(_ sender: Any) {
let button:NSButton = sender as! NSButton
let id:String = button.identifier!.rawValue
print("===========>"+id)
}

On your code you are actually trying to access the accessibility identifier which is a different thing. To identify the radio button you should use tags. Set a tag for the button and then read it like this.
#IBAction func text_radio_changed(_ sender: Any) {
let button:NSButton = sender as! NSButton
let id:Int = button.tag
print("===========>"+id)
}
Note: You can actually do use the accessibility id to do the same thing. Check this other similar post.
Update: The answer by "Willeke" seems better (if it works), I am used to developing for iOS and I wasn't aware there is an identifier property for NSButtons.

Related

How can I get the title of a NSMenuItem in a submenu of a NSPopUpButton?

I can get the name of a NSMenuItem at the top level of the NSMenu of a NSPopUpButton.
I do this by adding an action to the NSPopUpButton:
#IBAction func menuDropdownAction(_ sender: Any) {
let titleOfSelectedItem = (sender as AnyObject).titleOfSelectedItem
print (titleOfSelectedItem! as Any)
}
But if I add a submenu to the NSMenu it just returns nil.
It seems to me that .titleOfSelectedItem applied to the NSPopUpButton should work for items buried in its submenus, but it seems not!
Any assistance would be gratefully accepted, there is a similar question, but its over 10 years old for cocoa and was no use to me. link
Swift is a strong typed language and you don't care about the type by writing Any and AnyObject.
Replace the sender with the real type
#IBAction func menuDropdownAction(_ sender: NSPopUpButton) {
then you can access all properties of the popup button
let titleOfSelectedItem = sender.titleOfSelectedItem
let menu = sender.menu!
let firstMenuItem = menu.item(at: 0)!
let subMenu = firstMenuItem.submenu!

How to Pass the data given in UITextField to another variable on another class

So i have a UITextField named apiTextField and a function of the saveButton :
func saveButton(_ sender: Any) {
}
I want when the user writes to the UITextField and press the saveButton that text the user wrote be passed to a variable which is called var baseURL:String? in another class.
I didn't find anything related to UITextField so i decided to make this question, another similar one is 10 years old!.
var anotherClass = AnotherClass()
func saveButton(_ sender: Any) {
guard let text = apiTextField.text, !text.isEmpty else { return }
anotherClass.baseURL = text
}
Is that what you are looking for?

Swift 4 - Creating a common function for multiple buttons

I'm wondering if there is a more efficient way to code an action that is the same with the exception of which button has been pressed and which item in a struct it relates to. Basically, I have a struct of 10 variables all of which are a boolean type and I have 10 buttons. When the user presses the button, I want to check whether it has already been pressed (using the struct) and then change the background of the button depending on the state and reverse the state. I've copied my current code for one of the buttons but thought I should be able to avoid doing this 10 times!
#IBAction func architectureButtonPressed(_ sender: Any) {
if myInterests.architecture {
myInterests.architecture = false
architectureButton.setBackgroundImage(imageUncheckedNarrow, for: .normal)
} else {
myInterests.architecture = true
architectureButton.setBackgroundImage(imageCheckedNarrow, for: .normal)
}
}
Well one simple way is to have each UIButton point to the same architectureButtonPressed IBAction method. Since the button that's pressed is passed into the method (sender) you can consult it's tag property to know the index of which field in your struct should be updated. (And then you might want to change your struct to just store an array of 10 bools, but up to you).
Then for each UIButton, whether programmatically in storyboard or nib, you'd assign the appropriate index value to the button's tag field.
Create yours IBOutlet for each button.
Create a array and store all buttons like : var arrayButtons : [UIButton] = []
arrayButtons.append[button1]
arrayButtons.append[button2]
...
Create a array of booleans to store true/false: var arrayBools : [Bool] = [] and initialize if some value.
Note that the indexes of the arrayButtons and arrayBools must be same related.
Create selector function to listen touch buttons.
button.addTarget(self, action: #selector(my_func), for: .touchUpInside)
#objc func my_func(_ sender : UIButton) {
for i in 0...arrayButtons.size-1 {
if arrayButtons[i] == sender {
if arrayBooleans[i] {
arrayBooleans[i] = false
arrayButtons[i].setImage()
} else {
arrayBooleans[i] = true
arrayButtons[i].setImage()
}
}
}
}
My suggestion is to manage the images in Interface Builder via State Config (Default/Selected)
Then assign an unique tag starting from 100 to each button and set the isSelected value in the IBAction to the corresponding struct member in a switch statement:
#IBAction func buttonPressed(_ sender: UIButton) {
switch sender.tag {
case 100: myInterests.architecture = sender.isSelected
case 101: myInterests.art = sender.isSelected
...
default: break
}
}
Alternatively use Swift's native KVC with WriteableKeypath
let keypaths : [WritableKeyPath<Interests,Bool>] = [\.architecture, \.art, \.fashion, \.history, \.localCulture, \.music, \.nature, \.shopping, \.sport, \.anything]
#IBAction func buttonPressed(_ sender: UIButton) {
let index = sender.tag - 100
let keypath = keypaths[index]
myInterests[keyPath: keypath] = sender.isSelected
}

How to delete a character from a UI Label in Swift?

I am new to Swift and I am having issues with deleting a character from a UI Label that I have created. I am trying to make a simple phone dailer app, and I am trying ti implement a backspace button. My UI Label is called DailerLabel, and I know I'm supposed to use the dropLast() function but I keep running into issues about mismatching types or unwrappers. I am not really sure what I am supposed to do here. I tried the thing in the commented code which didn't work, and then I tried what I listed below which doesn't either. Could anyone help me?
#IBAction func backspaceButtonPressed(_ sender: UIButton) {
if (!((DailerLabel.text?.isEmpty)!)) {
// DailerLabel.text?.substring(to: (DailerLabel.text?.index(before: (DailerLabel.text?.endIndex)!))!)
let temp = DailerLabel.text
temp?.dropLast()
DailerLabel.text = temp
}
You can try this one, replace label with your own UILabel
var name: String = label.text! //shauket , for example
name.remove(at: name.index(before: name.endIndex))
print(name) //shauke
label.text = name
print(label.text!)
You are very close. dropLast actually returns the string without the last character and you haven't stored that to anything so there is no change. You also have to conver back to String from Substring.
#IBAction func backspaceButtonPressed(_ sender: UIButton) {
if (!((DailerLabel.text?.isEmpty)!)) {
let temp = DailerLabel.text ?? ""
DailerLabel.text = String(temp.dropLast())
}
}
Here's a better version
#IBAction func backspaceButtonPressed(_ sender: UIButton) {
guard
let text = dialerLabel.text,
!text.isEmpty
else {
return
}
dialerLabel.text = String(text.dropLast())
}

Variable shared between view controllers of storyboard?

My app is split into 2 storyboards: a character selection one and a main application one. When the user selects a character the app segues's to the main application, and all the views of that storyboard should now relate to the character the user selected.
I'm trying to find out the best way to share a String that will have the selected character's information between all the main application storyboard's views. Right now I'm using UserDefaults to just set a global variable:
func loadMainApp(sender: UITapGestureRecognizer) {
let currentCharcter = allCharacters[(sender.view?.tag)!]
let defaults: UserDefaults = UserDefaults.standard
defaults.setValue(currentCharacter, forKey: "CurrentCharacter")
performSegue(withIdentifier: "MainAppSegue", sender: self)
}
From there all the view controllers in the Main App storyboard can fetch the string from UserDefaults.
Is this the best way of doing such a thing or is there a better way?
The better way is to pass the character to the viewController you are segueing to, and the easiest way to do that is with prepare(for segue. If you change your performSegue call to pass the sender on by saying performSegue(withIdentifier: "MainAppSegue", sender: sender) you will be able to access that in prepare(for like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//Safely check to make sure this is the correct segue by unwrapping the sender and checking the segue identifier
if let tapGesture = sender as? UITapGestureRecognizer, let tapGestureView = sender.view, let mainViewController = segue.destination as? MainViewController, segue.identifier == "MainAppSegue" {
//Get a reference to the character that was selected
let currentCharacter = allCharacters[tapGestureView.tag]
//Pass the character to the new viewController
mainViewController.character = currentCharacter
}
}
I made a couple assumptions about the name of the viewController you are performing the segue to, and assumed it has a variable called character where you can send your character. Your new viewController now has a reference to the character.
If I understand you well. Personally I am using Singeltons for achieving Global variable between Views rather than UserDefaults
class SomeClass{
static let sharedInstance = SomeClass()
var someString = "This String is same from any class"
}
Usage inside of some function :
SomeClass.sharedInstance.someString = "Changing Global String"