why (self.account.text?.isEmpty)! is required '!' - swift

if (self.account.text?.isEmpty)! {
}
I just write down this function in ViewDidLoad().
(account is a textfield)
I think that 'self.account.text' can be nil, and 'self.account.text?' is okay.
but I don't know why 'self.account.text?.isEmpty' require '!' - unwrapping.
'self.account.text?.isEmpty' is right, isn't it....?
I always appreciate all answers.

It's because the expression self.account.text?.isEmpty has a value of type bool or the value nil, and you can't use nil as an if-condition.
Using ! here is wrong. If text is nil then the code will crash.
Instead write:
if self.account.text?.isEmpty == true { ... }
// or equivalently:
if self.account.text?.isEmpty ?? false { ... }
if you want to skip the if when text is nil, or:
if self.account.text?.isEmpty != false { ... }
// or equivalently:
if self.account.text?.isEmpty ?? true { ... }
if you want to enter the if when text is nil.
If text should never be nil here then you can just use ! directly after text:
if self.account.text!.isEmpty { ... }

self.account.text
is optional boolean value so it will be nil or boolean. unwrapping the boolean must check it is equal to true or false like in this way.otherwise it will crash because of nil value.
import UIKit
var isempty: Bool?
if isempty == true
{
print("i am empty")
}
else
{
print("hy i am not empty")
}
//it will print "Hy i am not empty" because isempty has nil

Related

How to check the string doesn’t contain any letters in swift?

i have trouble during making the letter checker, my code is like this: if !containLetters(“1234h”){print(“pass”)}
my function is
func containsOnlyNum(input: String) -> Bool {
var ok = false
for chr in input {
for check in "1234567890.-"{
if chr == check{
ok = true
}
}
if ok != true{
return false
}
}
return true
}
If I check for “h” then didn’t pass, but if i check for ”1h” then it still pass! Please help me to fix this problem. I will give a big thank for anyone who helped me
The simplest way to fix the algorithm is this way:
func containsOnlyNum(input: String) -> Bool {
// check every character
for chr in input {
var isNum = false
for check in "1234567890.-"{
if chr == check {
isNum = true
// if we have found a valid one, we can break the iteration
break
}
}
if !isNum {
return false
}
}
return true
}
print(containsOnlyNum(input: "1234")) // true
print(containsOnlyNum(input: "1234h")) // false
However, then you can directly simplify it to:
func containsOnlyNum(input: String) -> Bool {
return input.allSatisfy { chr in
"1234567890.-".contains(chr)
}
}
which does exatly the same but uses allSatisfy and contains functions, which represent the logical operators ALL and EXISTS.
However, programmers normally use regular expressions for similar tasks:
func containsOnlyNum(input: String) -> Bool {
return input.range(of: "^[0-9.\\-]+$", options: .regularExpression) != nil
}
You can check that a string contains only the characters you're interested in like this:
extension String {
var containsOnlyNum: Bool {
let wanted = CharacterSet.decimalDigits
.union(CharacterSet(charactersIn: "-."))
return unicodeScalars
.allSatisfy(wanted.contains)
}
}
"-12.34".containsOnlyNum // true
"A1234".containsOnlyNum // false
But if you are interested in numbers, then this is a problem:
"-12.-34.".containsOnlyNum // true
Instead, you can just try casting the string to a double and see if it is a number or not
Double("1234") != nil // true, a number
Double("-1.234") != nil // true, a number
Double("A1234") != nil // false, not a number
Double("-12.-34.") != nil // false, not a number
Which is almost right unless you don't want this case:
Double("1234e2") != nil // true, a number
But you can use both checks if you don't want to allow that, or else if you are able to parse a Double from the input you can just do the cast.

Swift: Setting variables if not equalling nil

I'm using Swift and I'm wondering how to achieve this in 1 line of code:
If a != nil, myVariable = a
else if a == nil, myVariable = b
I need to do this so it fits with
var myVariable = a {
didSet{
//Do something
}
}
Is there a way to do this in 1 line so I don't have to change it elsewhere and trigger the didSet{}?
Something like this:
if var myVariable = a
else myVariable = b {
didSet{
//Do something
}
}
Or...
var if a != nil {myVariable = a}
else {myVariable = b} {
didSet{
//Do something
}
}
I know this may take some time to realise what I mean, I tried my best to explain it.
EDIT --->
The compiler says:
Left side of nil coalescing operator '??' has a non-optional type '[[Bool]]', so the right side is never used
and
Treating a forced downcast to '[[Bool]]' as optional will never produce 'nil'
This is what it looks like using a coalescing operator:
var purchased =
UserDefaults.standard.array(forKey: "purchased") as! [[Bool]] ??
[[true, false], [true, false], [true, false], [true, false], [true, false]] { //a is left, b is right
didSet {
//Do something
}
}
Any ideas would be greatly appreciated. Thank you.
How about
var myVariable = a ?? b
This sets myVariable to a except for the case when a == nil, then it sets myVariable to b. didSet would be called once with the respective value. It is called a "nil coalescing operator".
Your edited questions shows that a in your case cannot be nil because you force unwrap the array (with as!). Instead you should conditionally unwrap it (as?), so that your code can check for nil and use the hard-coded default instead.
//Sets my variable to a if a != nil, else b.
var myVaraiable = (a != nil ? a : b)
Since a is optional and b is not, it would be more like
var myVariable = (a != nil ? a! : b)

What is this Swift ternary operator? A == B ? C : D

I inherited an iOS app that is crashing at this line (unexpected nil). What is your best interpretation of what is going on here?
indexPath.row.number == selectedItem ? cell.deselectStyle() : cell.dedeselectStyle()
The cell.deselectStyle() and cell.dedeselectStyle() functions don't return anything. I can't seem to find any information on what is going on here. selectedItem is a NSNumber!.
NSNumber could be nil leading to a crash if you try to access it. Add a guard to check that is not nil.
guard let s = selectedItem?.intValue else {
cell.dedeselectStyle
return
}
indexPath.row == s ? cell.deselectStyle() : cell.dedeselectStyle()
I've assumed it's safe to assume the cell is not selected if the NSNumber is nil, however you should really check the logic in your code to be sure.
This is a conditional statement. Think of it like an if statement:
if indexPath.row.number == selectedItem {
cell.deselectStyle()
} else {
cell.dedeselectStyle()
}
If the condition is true, the code between ? and : will be executed. If not, the code after the : will be called. You should know that the ? has nothing to do with Optionals.
In your case, selectedItem seems to be nil. Therefore, you need to either only execute the code if selectedItem is not nil, you could use an if let statement:
if let selectedItem = selectedItem {
indexPath.row.number == selectedItem ? cell.deselectStyle() : cell.dedeselectStyle()
}
Or, you could insert a default value that will be used instead of selectedItem if it is nil:
indexPath.row.number == (selectedItem ?? false) ? cell.deselectStyle() : cell.dedeselectStyle()
The code above will use either the value of selectedItem, or false, if selectedItem is nil. You can leave out the parentheses, I just put them there for better visualization.
I hope this helps :)
Probably The reason the crash is that selectedItem is nil; I think you misunderstand the difference between the ? for optionals and the ? for implementing the ternary operator.
The ternary operator has nothing to do with -implicitly- checking if the value is nil, you might need to implement a guard statement or if let (optional binding) before the step of doing the ternary operator comparison.
It should be similar to:
if let selectedItem = selectedItem {
indexPath.row.number == selectedItem ? cell.deselectStyle() : cell.dedeselectStyle()
} else {
print("selectedItem is nil!")
}
Or, if an early return required:
guard let selectedItem = selectedItem else {
print("selectedItem is nil!")
return
}
indexPath.row.number == selectedItem ? cell.deselectStyle() : cell.dedeselectStyle()
To make it more clear to you, check the following code snippet:
let nilValue: String! = nil
if nilValue == "test" { }
// fatal error: unexpectedly found nil while unwrapping an Optional value
// OR
let isValueTest: Bool = (nilValue == "test") ? true : false
// fatal error: unexpectedly found nil while unwrapping an Optional value
That's why you should unwrap the value before accessing it.
to better understand it, play in your Playground
func f0() -> Int { print(0); return 0 }
func f1() -> Int { print(1); return 1 }
func fa() -> String { print("a"); return "a" }
[true, false, true, true].forEach {
$0 ? f0() : f1() // warning: expression of type 'Int' is unused
}
[true, false, true, true].forEach {
_ = $0 ? f0() : f1() // OK
}
[true, false, true, true].forEach {
$0 ? f0() : fa() // error: result values in '? :' expression have mismatching types 'Int' and 'String'
}
[true, false, true, true].forEach {
_ = $0 ? ( 1 == f0()) : ( "A" == fa()) // OK
}

swift reflection causes impossible nil value for any

I'm trying to use swift reflection to check for changes in objects so I can send only changed properties up to the server. Some of my properties are optional. To compare those values, I need to unwrap them but, of course, you can ONLY unwrap actual values, not nil values. So, I need to check if one of the values is nil before I compare them.
In my playground, I tried the following:
import UIKit
class myClass
{
var fieldOne:String?
var fieldTwo:Int?
var fieldThree:Float?
}
var oneMyClass = myClass()
oneMyClass.fieldOne = "blah"
oneMyClass.fieldThree = 3.5
var oneOtherClass = myClass()
oneOtherClass.fieldOne = "stuff"
oneOtherClass.fieldTwo = 3
let aMirror = Mirror(reflecting: oneMyClass)
let bMirror = Mirror(reflecting: oneOtherClass)
for thing in aMirror.children
{
for thing2 in bMirror.children
{
if thing.label! == thing2.label!
{
print("property: \(thing.label!)")
print("before: \(thing.value)")
print("after: \(thing2.value)")
print("")
//let myTest = thing.value == nil ? "nil" : "not nil"
}
}
}
And it generates the following output:
property: fieldOne
before: Optional("blah")
after: Optional("stuff")
property: fieldTwo
before: nil
after: Optional(3)
property: fieldThree
before: Optional(3.5)
after: nil
As you can see, the expected properties are displayed as "nil". However, if you uncomment the let statement, you get an error stating:
playground52.swift:37:38: error: value of type 'Any' (aka 'protocol<>') can never be nil, comparison isn't allowed
And yet, we know from the output that it IS nil. How can this be and what can I do about it?
Based on this answer, I recommend using if case Optional<Any>.some(_).
For example:
aMirror.children.forEach {
guard let propertyName = $0.label else { return }
if case Optional<Any>.some(_) = $0.value {
print("property: \(propertyName) is not nil")
} else {
print("property: \(propertyName) is nil")
}
}
Thats look like some sort of bug. Look at that
let x = childMirror.value == nil ? "Nil" : "Not Nil" //dont compile.
let y = { (value:Any?) in
return value == nil ? "Nil" : "Not Nil"
}
let z = y(childMirror.value) //compile, but doesn't evaluate.
I guess the problem is because Any can store a Optional, but can't be wrapped around one. Try this:
func getValue(unknownValue:Any) -> Any {
let value = Mirror(reflecting: unknownValue)
if value.displayStyle != .Optional || value.children.count != 0 {
return "Not Nil"
} else {
return "Nil"
}
}

"If" statement not working with optional value

My problem is that I have some text fields that the user enters in numbers, the entered numbers then get saved to the corresponding variable.
However if the user doesn't enter a number and leaves it blank, the text field has a value of 'nil' and so would crash if unwrapped.
So I used an if statement to only unwrap if the contents of the test field are NOT nil, however this doesn't work. My program still unwraps it and crashes because the value is nil...
I don't understand how my if statement is not catching this.
On another note, how do I change my if statement to only allow Int values to be unwrapped and stored, strings or anything else would be ignored.
#IBAction func UpdateSettings() {
if CriticalRaindays.text != nil {
crit_raindays = CriticalRaindays.text.toInt()!
}
if EvapLess.text != nil {
et_raindays_lessthan_11 = EvapLess.text.toInt()!
}
if EvapMore.text != nil {
et_raindays_morethan_11 = EvapMore.text.toInt()!
}
if MaxWaterStorage.text != nil {
max_h2Ostore = MaxWaterStorage.text.toInt()!
}
if CarryForward.text != nil {
carry_forward = CarryForward.text.toInt()!
}
}
Your issue is that while the text exists, it doesn't mean toInt() will return a value.
Say the text was abc, CriticalRaindays.text != nil would be true but CriticalRaindays.text.toInt()! can still be nil, because abc cannot be converted to an Int.
The exact cause of your crash is likely that .text is equal to "", the empty string. It's not nil, but definitely not an Int either.
The better solution is to use optional binding to check the integer conversion and see if that passes, instead of merely the string existing:
if let rainDays = CriticalRaindays.text.toInt() {
crit_raindays = rainDays
}
If that doesn't compile, you possibly need to do Optional chaining:
if let rainDays = CriticalRaindays.text?.toInt()
Not on a Mac atm so can't test it for you but hope this makes sense!
Why not use an if let to unwrap on if the the text field's text is non-nil?
if let textString = self.textField.text as String! {
// do something with textString, we know it contains a value
}
In your ViewDidLoad, set CarryForward.text = "" This way it will never be nil
Edit:
To check if a textfield is empty, you can use this:
if (CarryForward.text.isEmpty) {
value = 10
}
else {
value = CarryForward.text
}