changing the value of a variable from another class in swift - ios

I have created a custom UISegment Control
#IBDesignable class CardsSegmentedControl: UIControl {
private var labels = [UILabel]()
var thumbView = UIView()
var items: [String] = ["Saved Cards", "Add Card"] {
didSet {
setupLabels()
}
}
var selectedIndex : Int = 0 {
didSet {
displayNewSelectedIndex()
}
}
....
}
Now I wish to change the value of the variable selectedIndex in the viewController where I am adding this custom segment control in.
I guess it is a problem of how to access/change variables from another class.
I tried to create a class func which would set the value of the selectedIndex but I cannot get it to access the selectedIndex variable either.
Still pretty new to Swift so please bear with me.

// Inside your ViewController class, create a new instance of your custom class
var cardSegmentedControl = CardSegmentedControl()
// here, change its property value
cardSegmentedControl.selectedIndex = 1

Related

How to assign a String value to button.tag [duplicate]

Is there any way of sending string value to UIButton tag? I know tag is Int type but I need to send string value.
let myButton: UIButton = {
let button = UIButton()
button.tag = "123"
return button
}()
I need to send button.tag as a string
Create a custom class of UIButton and create one String type property like customTag
class CustomButton: UIButton {
var customTag:String = ""
}
Assign the custom class to your UIButton and use String type tag by following code.
let myButton: CustomButton = {
let button = CustomButton()
button.customTag = "ABC"
return button
}()
Instead of tag you can do it using accessibilityLabel.
btn.accessibilityLabel = "ABC"
One more answer.
Instead of accessibilityLabel / accessibilityIdentifier or any other related to accessibility , let us go for layer.name
Button.layer.name = "abc123"
#IBAction func wasPressed(_ sender: UIButton) {
print("was Pressed \(sender.layer.name)")
}
Reason:
Incase, we are in need to set accessibility for each and every screen, at that time it might affect.
But, if we are in need to add another layer for UIButton, it will not affect
Unfortunatly, the tag is just an integer value.
What you could do is:
Subclass UIButton and add your own property
Use associated objects, like in https://gist.github.com/mjjimenez/7956352
Use enums for the tag; maybe add an extension to access them
(Mis)use the accessibilityIdentifier
Just create extension of UIButton or NSObject.
extension NSObject {
private struct AssociatedKeys {
static var DescriptiveName = "strCustomTag"
}
var strCustomTag: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.DescriptiveName,
newValue as NSString?,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
}
}
Refer below code to set the value of strCustomTag
let myButton: UIButton = {
let button = UIButton()
button.strCustomTag = "ABC"
return button
}()
Get Value
print(view.strCustomTag)
If you create an extension of NSObject
strCustomTag is accessible from any class or any UI Elements such as
UIButton, UITextField, UIView etc.
No need to change in exsting storyboard OR XIB file
There is no way to set the tag to String because its type is Int.
Most probably you will no need to set it anyway because using the tag of UIView is not a common technique.
If you still want to use similar solution (I recommend not to) then you may use the accessibilityIdentifier property which is String.
Also you can create a custom subclass of UIButton with custom String property and to use this custom subclass instead of UIButton
You can create custom class for button then you can pass any kind of values by just define the property in the custom class.
Example: I want to pass the String and Int both values in Button So I will pass Int in to button tag and string will be passed in custom button property.
class CustomButton: UIButton {
var stringToPass: String = ""
}
ViewController Class
class HomeVC: UIViewController {
let customButton = CustomButton()
override func viewDidLoad() {
super.viewDidLoad()
customButton.stringToPass = "Your String"
}
}

Apply property wrapper in superclass owned property

I have created my own property wrapper for the theming of UI components like UIView, UILabel etc.
class MyUIViewController: UIViewController {
#Theme private override var view: UIView! // it doesnt work!!!
#Theme private var myCustomView: UIView! // it works!!
}
in this case, i will get a compile error "Cannot override with a stored property 'view'"
I know that the view is a property of UIViewController. Do you know if there is any possible way to apply the property wrapper to a stored(superclass) property? any suggestions would be appreciated :) thanks a lot!
I found a way to do that but it's more like a hack than a good implementation (so I would not recommend it), and I haven't fully tested it (as it really on the UIViewController view loading mechanism, this can lead to some undefined behavior).
That said, in the property wrapper documentation you can find a "translation example" that explains how property wrapper works.
#Lazy var foo = 1738
// translates to:
private var _foo: Lazy<Int> = Lazy<Int>(wrappedValue: 1738)
var foo: Int {
get { return _foo.wrappedValue }
set { _foo.wrappedValue = newValue }
}
So we can imitate this to manually wrap a superclass property.
Note that doing this on the view property is a bit special as the view is not loaded during the view controller initialization, but more like a lazy var.
#propertyWrapper
struct Theme<WrappedValue: UIView> {
var wrappedValue: WrappedValue?
}
class Controller: UIViewController {
override func loadView() {
super.loadView()
_view.wrappedValue = view
}
private var _view: Theme<UIView> = .init()
override var view: UIView! {
get {
if _view.wrappedValue == nil {
// This is a trick I would not recommend using, but basically this line
// forces the UIViewController to load its view and trigger the
// loadView() method.
_ = super.view
}
return _view.wrappedValue
}
set {
_view.wrappedValue = newValue
}
}
}
I made the wrapped value in the property wrapper optional because the view property is nil during the initialization process (as the view is not yet loaded)

How to send string data to UIButton tag?

Is there any way of sending string value to UIButton tag? I know tag is Int type but I need to send string value.
let myButton: UIButton = {
let button = UIButton()
button.tag = "123"
return button
}()
I need to send button.tag as a string
Create a custom class of UIButton and create one String type property like customTag
class CustomButton: UIButton {
var customTag:String = ""
}
Assign the custom class to your UIButton and use String type tag by following code.
let myButton: CustomButton = {
let button = CustomButton()
button.customTag = "ABC"
return button
}()
Instead of tag you can do it using accessibilityLabel.
btn.accessibilityLabel = "ABC"
One more answer.
Instead of accessibilityLabel / accessibilityIdentifier or any other related to accessibility , let us go for layer.name
Button.layer.name = "abc123"
#IBAction func wasPressed(_ sender: UIButton) {
print("was Pressed \(sender.layer.name)")
}
Reason:
Incase, we are in need to set accessibility for each and every screen, at that time it might affect.
But, if we are in need to add another layer for UIButton, it will not affect
Unfortunatly, the tag is just an integer value.
What you could do is:
Subclass UIButton and add your own property
Use associated objects, like in https://gist.github.com/mjjimenez/7956352
Use enums for the tag; maybe add an extension to access them
(Mis)use the accessibilityIdentifier
Just create extension of UIButton or NSObject.
extension NSObject {
private struct AssociatedKeys {
static var DescriptiveName = "strCustomTag"
}
var strCustomTag: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.DescriptiveName,
newValue as NSString?,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
}
}
Refer below code to set the value of strCustomTag
let myButton: UIButton = {
let button = UIButton()
button.strCustomTag = "ABC"
return button
}()
Get Value
print(view.strCustomTag)
If you create an extension of NSObject
strCustomTag is accessible from any class or any UI Elements such as
UIButton, UITextField, UIView etc.
No need to change in exsting storyboard OR XIB file
There is no way to set the tag to String because its type is Int.
Most probably you will no need to set it anyway because using the tag of UIView is not a common technique.
If you still want to use similar solution (I recommend not to) then you may use the accessibilityIdentifier property which is String.
Also you can create a custom subclass of UIButton with custom String property and to use this custom subclass instead of UIButton
You can create custom class for button then you can pass any kind of values by just define the property in the custom class.
Example: I want to pass the String and Int both values in Button So I will pass Int in to button tag and string will be passed in custom button property.
class CustomButton: UIButton {
var stringToPass: String = ""
}
ViewController Class
class HomeVC: UIViewController {
let customButton = CustomButton()
override func viewDidLoad() {
super.viewDidLoad()
customButton.stringToPass = "Your String"
}
}

Access TextField from another class or method without storyboard

Okay, this might be one of the most basic questions ever, but all answers I find use storyboard to declare an outlet for a label, textfield or whatever element that needs to be changed. I, however, don't use storyboards and write everything in code. Now I have a function setupViews, where I define a textfield:
let usernameInput = UITextField()
Now, I can perfectly set the text or placeholder or whatever inside this setupViews() class, but how can I access it outside? For example, if I have a function logIn(), I want to call usernameInput.text and use it in this function.
Someone who can point me in the right direction? Do I need to declare this textfield globally, in another file, or something else?
When I create my views in code I always associate a property with the view that has all those various display values.
I have not tested this code to see but hopefully the following will give you an idea.
import UIKit
struct {
var name: String
}
class CustomViewController : UIViewController {
// some struct which contains data for view
var customViewData : ViewDataInfo? {
didSet {
labelOnScreen.text = customViewData.name
}
}
var labelOnScreen: UILabel = {
let label = UILabel()
label.text = "Placeholder information..."
// stuff auto layout
label.translateAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
private func setupView() {
view.addSubview(label)
// set your constraints here
}
}

Add a string property to a UIButton in Swift

How can I associate a string property with a UIButton in Swift? I don't want the string to appear as the button text, simply to be assigned to the button as an identifier or a key. Here is what I have so far:
func createAnswerButtons() {
var index:Int
for index = 0; index < self.currentQuestion?.answers.count; index++ {
// Create an answer button view
var answer:AnswerButtonView = AnswerButtonView()
selection.setTranslatesAutoresizingMaskIntoConstraints(false)
// Place into content view
self.scrollViewContentView.addSubview(answer)
// Add a tapped gesture recognizer to the button
let tapGesture:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("answerTapped:"))
answer.addGestureRecognizer(tapGesture)
// Add constraints etc
// Set the answer button text
let answerText = self.currentQuestion!.answers[index]
answer.setAnswerText(answerText)
// Set the identifier for each answer button
self.identifier = self.currentQuestion!.answerIdentifier[index]
// Add to the selection button array
self.answerButtonArray.append(answer)
}
So I think I need something after
// Set the identifier for each answer
self.identifier = self.currentQuestion!.answerIdentifier[index]
To assign the identifier to the button.
The reason for this is I'm trying to implement a decision tree logic so that I can keep track of each answer button that is tapped to generate a code string that will correspond to a final result.
Using the Objective-C runtime, we can add properties to classes at runtime:
extension UIButton {
private struct AssociatedKeys {
static var DescriptiveName = "nsh_DescriptiveName"
}
#IBInspectable var descriptiveName: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.DescriptiveName,
newValue as NSString?,
UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)
)
}
}
}
}
Adding #IBInspectable also lets us set the descriptiveName property through Interface Builder.
For more about the Objective-C runtime, I recommend you check out this NSHipster article.
You can use the accessibility identifier (button.accessibilityIdentifier), if the button you want to identify should have a unique identifier (this matters if you're ever writing UI tests).
You can also subclass UIButton and add a variable buttonIdentifier.
class IdentifiedButton: UIButton {
var buttonIdentifier: String?
}
You can use accessibilityIdentifier property of UIButton.
#IBOutlet weak var button: UIButton!
button.accessibilityIdentifier = "Some useful text"
Use
button.accessibilityIdentifier = "some text"
istead of tag.
You can create an array with the strings you want associated with the button. Then set the buttons tag to the index of the string you want associated with the button. Hence:
var myStrings = ["First","Second","Third"]
button.tag = //insert a number corresponding to the string index in myStrings that you want for the button
func buttonPressed(sender: UIButton){
var selectedString = myString[sender.tag]
}

Resources