Swift: Using Int in UILabel inside View Controller - swift

I've set up an if statement which does things depending on an int value stored in a UILabel, however, my code can't determine the value of the int inside the label.
This is because the if statement runs within the viewdidload function. I'm basically looking for how I can pass the label value to my view. I'm struggling to make it work.
Here's the code:
override func viewDidLoad()
{
// If statement
var NumberRead = Int(Number.text!)
if NumberRead! <= 2 {
Picture.image = Pic1
} else {
Picture.image = Pic2
}
}
#IBOutlet weak var Number: UILabel!
Any suggestions for better ways to handle this would be amazing.
Thanks

I don't think the problem is that you use this code in viewDidLoad, but that your UILabel is empty when you run the code and the code is unwrapping a nil value. You have to set the UILabel Number to a value before you use the if statement.
I don't know what value you expect in the Number label, but either set it with an initial value, e.g. 0, or when this view controller is called through segueing from another view controller pass on the value the label should have. The code should then work fine.

How about:
set the default image to pic2, then use optional binding to check the value
Picture.image = Pic2
if let numTxt = Number.text {
if let num = Int(numTxt) {
if num <= 2 {
Picture.image = Pic1
}
}
}

You should separate your data and logic from the view. It is absurd to put a value into a label and try to interpret it. Please consider reading up on the MVC (model view controller) pattern which is the underpinning of iOS.
Your view controller should have a variable, say number to keep track of the value that determines which image to show.
var number: Int = 0 {
didSet {
imageView.image = number <= 2 ? pic1 : pic2
label.text = "\(number)"
}
}
On naming
Your variable names are also a mess. By convention variables are lowerCamelCase. If you are naming an UIImageView, the name picture is too generic and could be misleading. Also avoid names like pic1, pic2, better is something like activeImage, inactiveImage.

Related

Binary operator '==' cannot be applied to operands of type 'UILabel?' and 'String'

Error : Binary operator '==' cannot be applied to operands of type 'UILabel?' and 'String'
import UIKit
class ViewController: UIViewController {
let Soft = 5
let Medium = 8
let Hard = 12
#IBAction func hardnessSelected(_ sender: UIButton) {
let hardness = sender.titleLabel
if hardness == "Soft"{
print(Soft)
}
else if hardness == "Medium"{
print (Medium)
}
else {
print (Hard)
}
}
}
How can i fix this error?
You don't give the line number the error is on, but looking at the text it mentions operation == so I'm guessing it's one of these:
if hardness == "Soft"{
else if hardness == "Medium"{
"Soft" and "Medium" are the strings, so hardness must be a 'UILabel?. Those types can't be compared to each other. You must want the text displayed on the button? Looking at the UILabel docs, there is a text property so you probably want to change this line to grab the string representing the button's text:
let hardness = sender.titleLabel.text
Are you using dynamic buttons? It would be less error prone to just compare the sender with the button your are checking for. Comparing hard-coded strings to the text of the button can lead to run-time errors. Maybe you didn't get the case right, misspelled the text, or decided to localize later so the text may be different in a different language. These errors wouldn't be caught at compile-time.
You're trying to compare two different types. To get the actual text of UILabel, you'll need hardness.text.
UIButton.titleLabel is a UILabel and it stores its text in UILabel.text property:
let hardness = sender.titleLabel.text
In the case of UIButton you can also access UIButton.currentTitle property:
let hardness = sender.currentTitle
An UIButton exposes its label through an UILabel that manage the drawing of its text. Thus change:
let hardness = sender.titleLabel
to
let hardness = sender.titleLabel.text
UIKit docs says:
UIButton
var titleLabel: UILabel?
A view that displays the value of the currentTitle property for a button.
and:
UILabel
var text: String?
The current text that is displayed by the label.
There is also a more direct way using the currentTitle:
UIButton
var currentTitle: String?
The current title that is displayed on the button.
Thus:
let hardness = sender.currentTitle
will also work.

How to use a button to add 4 slider values together?

I've attempted this multiple times, 1st by just trying to add the labels under my sliders (see picture below), but labels do not support integers. My newest attempt used 4 integer variables and set the label value to it, the only thing wrong with this method is it only works with one label, if I do this for all 4 I cannot add them together. `
var aValue: Int {
didSet {
mathCriAValue.text = "\(aValue)"
}
}
#IBAction func mathCriAChanged( sender: UISlider) {
aValue = Int(sender.value)
}
Main storyboard
Create a reference to each of your sliders and each of your labels (i.e. make them all IBOutlet properties).
When your slider event is triggered, check which slider is the sender and update the text in the appropriate label:
labelA.text = "\(sliderA.value)"
Sum up the values of all sliders:
let total = sliderA.value + sliderB.value + sliderC.value + sliderD.value
Set the text in the total label (to which you also need a reference):
totalLabel.text = "\(total)"

Is it possible to perform a deep property comparison dynamically in Swift at runtime?

Let's say we have two instances of UILabel that, to us, are equivalent:
let label1 = UILabel()
label1.text = "Hello world"
let label2 = UILabel()
label2.text = "Hello world"
Let's say the two instances are in an array of type [UIView]:
let views: [UIView] = [label1, label2]
Is there any way to perform an equality check that would find these two instances of UIView to be equivalent without knowing which type they are ahead of time (and therefore which common properties to compare on)?
(Any way to use the fact that these instances are both have a dynamicType of UILabel and dynamically run through the key/value properties of the UILabel class and compare each value that can be compared?)
What's happening:
label1 == label2 // false
views[0] == views[1] // false
What's desired:
areTheSame(label1, label2) // true
areTheSame(views[0], views[1]) // true
We are looking for a way to compare two separate instances, so we can't use ===.
Swift has no reflection so this is not possible. We can't even get a list of attributes.
Also note that for many types there is no definition of equality. Even comparing two floating point values is a problem.
Exactly for this reason we have the Equatable protocol. If you want to compare types, define equality on them. That equality can then go as deep as needed, without the need for any dynamic (unsafe) behavior.
Just to explain another corner case, for example, on UILabel there are some properties that you definitely don't want to compare, namely things like nextResponder or superview. Trying to deep compare those properties would actually end up in a loop. Usually it's not possible to compare two objects for equality without knowing exactly what should and what should not be compared.
Something like this should work:
let views: [UIView] = [label1, label2]
func areTheSameLabel(view1: UIView, _ view2: UIView) -> Bool {
guard let label1 = view1 as? UILabel,
let label2 = view2 as? UILabel else { return false }
return label1.text = label2.text
}
print(areTheSameLabel(label1, label2)) // Should print "true"
print(areTheSameLabel(views[0], views[1])) // Should print "true"
In response to your comments, I think the best avenue is to create a protocol:
protocol ViewEquatable {
var backgroundColor: UIColor? { get set }
var text: String? { get set }
// add any other properties you want to compare here...
}
Then write a function to compare them:
func ==<T: ViewComparable>(lhs: T, rhs: T) -> Bool {
return (lhs.backgroundColor == rhs.backgroundColor) &&
(lhs.text == rhs.text) &&
// whatever other comparison tests you need go here...
}
Something like that is probably your best option, though your requirements are too vague to give a complete answer...

Is there a way to prevent UILabel from type checking as UIView?

In my application I'm using the as operator to check what type of UI element I'm working with. I ran into an issue where UILabel is successfully checking as a view.
let label = UILabel()
label.text = "some text"
if let myLabel = label as? UIView {
print("its a view ") // succeeds
}
I also receive the warning that states:
warning: Conditional cast from 'UILabel' to 'UIView' always succeeds.
Question
Is there a way to add a constraint to this as check that will cause this check to fail as expected?
Try this:
if label.isMemberOfClass(UIView.self) {
print("its a view ") // succeeds
}
isMemberOfClass checks for UIView and no classes that inherit from it
Here's another approach, which is the one I needed for my particular situation as I was attempting to check a generic (T). Since I didn't specify that in the question, I'll won't accept this as the answer, but here is the solution:
if let label = obj as? UILabel where label.isMemberOfClass(UILabel.self) {
// ...
}
if let view = obj as? UIView where view.isMemberOfClass(UIView.self) {
// ...
}

Instance variables are nil after I try to set them

can't understand what's wrong here. I want to set some instance variables for view controller:
private func simpleViewControllerAtIndex(index: Int) -> UIViewController! {
let controller: SimpleTutorialController = storyboard?.instantiateViewControllerWithIdentifier("SimpleTutorialController") as! SimpleTutorialController
let mainText = "simple_main_\(index + 1)".localized
let detailText = "simple_detail_\(index + 1)".localized
print(mainText)
print(detailText)
controller.mainText? = mainText
controller.detailText? = detailText
print(controller.mainText)
print(controller.detailText)
return controller
}
and in logs I see something strange:
Aprendizagem
Palavra
nil
nil
How to solve the issue?
I'm sure you mean assigning the text variables without the question marks like this:
controller.mainText = mainText
controller.detailText = detailText
If you have the question marks the assignment only succeeds when the variable, in this case mainText, is not nil. It failed just because it was nil and thus stayed nil.
Change controller.mainText? to controller.mainText and similar for controller.detailText?.
When referring to optional variables, you don't need the ? when accessing them. You can use it when the variable is already set, but it is still not necessary.