Logical OR in mutiple condition with a nil expression - swift

Since 30 minutes I'm looking for a compiling solution for this objective-c condition that I want write in swift
if (session == nil || ![session isValid]) {
}

Most of the times, ![aThing aMethod] in Objective-C will translate to !aThing.aMethod in Swift.
Also, no need to wrap the boolean condition in parenthesis anymore.
if session == nil || !session.isValid {
}

If session is an optional, you can force unwrap it:
if session == nil || !session!.isValid() {
}

Related

Simplifying this Swift 4 logic

Complete newb to Swift 4 here. How can the following be more compactly written in Swift?
if myVar != nil {
if !myVarList.contains(myVar!) {
myVarList.append(myVar!)
}
}
I tried searching for examples of guard but couldn't find anything. I think Swift allows me to more compactly deal with the nil checking, but not sure how to go about it when combined with the nested conditional.
Just use if let to conditional unwrap the optional and do the other check in the same line, the comma represents a boolean AND operator
if let item = myVar, !myVarList.contains(item) {
myVarList.append(item)
}
If an (unwrapped) optional is going to be used after the check never write != nil
guard is only useful if an evaluation to false exits the scope
func foo() {
guard let item = myVar, !myVarList.contains(item) else { return }
myVarList.append(item)
}

How are consecutive if statements evaluated?

I have two if-statements to check, where one check is very costly. So I'm wondering which of the following statements would be the most performant:
1) I don't like the "pyramid of doom", but I'm sure it works fine
for customObject in array {
if customObject.isSimpleBool {
if customObject.isCostlyBool {
// do some stuff
}
}
}
2) I normally write like this ... but does it check isCostlyBool, if isSimpleBool is false?
for customObject in array {
if customObject.isSimpleBool && customObject.isCostlyBool {
// do some stuff
}
}
3) I know this works, but is it evaluated differently than solution 2?
for customObject in array {
if customObject.isSimpleBool, customObject.isCostlyBool {
// do some stuff
}
}
4) Is there another solution I have not found?
for customObject in array {
if customObject.isSimpleBool && customObject.isCostlyBool {
// do some stuff
}
}
This will work, I have used these kinds of statements with nil checks many times.
if (obj != nil && obj!.property == false) {}
and in cases of obj being nil, obj.property is never called(otherwise the application would crash)
Another solution:
array.filter { $0.isSimpleBool && $0.isCostlyBool }
.forEach { // do some stuff }
By the way: Solution 2 and 3 are different forms for the same thing.
As already stated in there comments, if we have boolean expression like this
a && b
and a is false then the result is evaluated as false only evaluating a.
So...
isSimpleBool && isCostlyBool
is evaluated as false without evaluating isCostlyBool when isSimpleBool is false.
This is a good reason why you should put the isSimpleBool value at the left side of the && operator.
Another syntax
Finally just another way of writing the same logic
for elm in array where elm.isSimpleBool && elm.isCostlyBool {
// do some stuff
}

Is there an operator in Swift that stops the evaluation of a multi expression conditional statement, as soon as the answer is clear?

In some programming language there is two other operator in addition with simple || and &&. these operators which I am going to call them _orif and _andif from now, can be used in place of && and || and They may help to improve efficiency and avoid errors, because evaluation of the conditional stops as soon as the answer is clear.
For example, evaluation of the following expression will stop halfway through (selectedSprite != nil) is false: So the rest of the conditional will be ignored and never evaluated, this will prevent a fatal error in this case : fatal error: unexpectedly found nil while unwrapping an Optional value and it will raise while reaches to the second expression because obviously nil does not responds to SpriteOwner().
if (selectedSprite != nil) &&
(selectedSprite.SpriteOwner().type == "Human")
{
println("a human selected")
}
I am looking for a replacement for && in above piece of code that could be used instead of the simple && operator, So if the first expression is evaluated as a false one (having the selectedSprite equal to nil) then the second expression be ignored at all.(since it does not have any influence on result)
Question:
Is there such a &&? operator in swift? if the answer is a No,
Is there a better way of doing that instead of nested if statements like I have written here :
if (selectedSprite != nil)
{
if (selectedSprite.SpriteOwner().type == "Human")
{
println("a human selected")
}
}
I am implementing an intelligent system with a lot of if clause in it and most of them are too complicated which adding a new if layer just to control nils is a real nightmare.
What you described is called short circuiting and Swift does have it. For example:
let a : Int? = nil
if a != nil && a! == 1 {
print("a is 1")
} else {
print("a is nil")
}
You can see a is never unwrapped. I think in your case, it's more likely that SpriteOwner() returns nil. the Swifty way to unwrap optional values is to use the let ... where ... syntax:
if let s = selectedSprite where s.SpriteOwner().type == "Human" {
println("a human selected")
}
The binary logical || and && operators in Swift 2 already behave as you describe. See "The Swift Programming Language", under "Logical AND Operator" : https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-ID60
If either value is false, the overall expression will also be false. In fact, if the first value is false, the second value won’t even be evaluated, because it can’t possibly make the overall expression equate to true. This is known as short-circuit evaluation.
Try executing the following in a playground; you will see that the second part of the conditional statement is never executed since the first part is false:
func isBar(rv: Bool) -> Bool {
print("side effect of isBar")
return rv
}
func isFoo() -> Bool {
print("side effect of isFoo")
return true
}
if isBar(false) && isFoo() {
print("both true")
}
You could achieve something similar with optional chaining:
class Sprite {
let otherSprite: Sprite?
let type: String
init(otherSprite: Sprite?, type: String) {
self.otherSprite = otherSprite
self.type = type
}
}
let innerSprite = Sprite(otherSprite: nil, type: "Human")
let outerSprite = Sprite(otherSprite: innerSprite, type: "Robot")
This doesn't execute the print statement because they otherSprite? comes back with a nil
if innerSprite.otherSprite?.type == "Human" {
print("A human selected")
}
This will print "A human selected" because the value of otherSprite is non-nil and the type's value == "Human"
if outerSprite.otherSprite?.type == "Human" {
print("A human selected")
}

Fatal error (null when unwrapped) at runtime

I was converting an objective-c code to swift, it compiled perfectly but gave me errors at runtime. It said:
fatal error: unexpectedly found nil while unwrapping an Optional value
Why is that ? The code ran perfectly in objective-c format.
swift version:
#IBAction func conn(sender: UIButton) {
if self.ble.CM.state != CBCentralManagerState.PoweredOn{
}
if self.ble.peripherals.count == 0 {
self.ble.findBLEPeripherals(2)
}
else {
if !(self.ble.activePeripheral != nil) {
self.ble.connectPeripheral(self.ble.peripherals.objectAtIndex(0) as! CBPeripheral)
}
}
btnScan.enabled = false
indConnecting.startAnimating()
}
This line is throwing an error at runtime:
if self.ble.peripherals.count == 0
objective-c version:
- (void) tryToConnectToBLEShield {
//Check core bluetooth state
if (self.ble.CM.state != CBCentralManagerStatePoweredOn)
//Check if any periphrals
if (self.ble.peripherals.count == 0)
[self.ble findBLEPeripherals:2.0];
else
if (! self.ble.activePeripheral)
[self.ble connectPeripheral:[self.ble.peripherals objectAtIndex:0]];
}
What is actually happening?
I am not familiar with the library, but based on your comment stating that peripherals is "for sure" the implicitly unwrapped optional, you'll want something like this:
if (self.ble.peripherals?.count ?? 0) == 0 {
self.ble.findPeripherals(2)
}
We can still use the optional binding & unwrapping tricks even with implicitly unwrapped optionals.
So, first we use the optional unwrap to get the count:
self.ble.peripherals?.count
This will either return the count of peripherals if peripherals is non-nil, or it will return nil safely.
Next, we tack on the Nil Coalescing Operator:
self.ble.peripherals?.count ?? 0
So, whenever the left half returns nil, we'll instead use 0.
And now we compare that with 0 as you were trying to do:
(self.ble?.peripherals?.count ?? 0) == 0
Which will return true when count is 0 or peripherals is nil. And ultimately this is the exact behavior of the Objective-C code, as method calls to Objective-C return NULL/NO/0 (which all return YES when ==-compared with 0).

Error in Apple's Swift documentation on forced unwrapping in if statements?

My iBook on "The Swift Programming Language" contains the following example of a feature describing forced unwrapping in if statements:
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
if convertedNumber {
println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
println("\(possibleNumber) could not be converted to an integer")
}
// prints "123 has an integer value of 123”
But this isn't working for me. Xcode (6.0.1) requires that I explicitly compare with nil as in
if (convertedNumber != nil) {
println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
println("\(possibleNumber) could not be converted to an integer")
}
Is my iBook wrong?
Yes it's wrong or, better, it's outdated. The behavior was changed on the release of 4/8/2014, and you can see the changelog here. The relevant part:
Optionals no longer implicitly evaluate to true when they have a value and false when they do not, to avoid confusion when working with optional Bool values. Instead, make an explicit check against nil with the == or != operators to find out if an optional contains a value.
That being said, you can drop the parenthesis
if convertedNumber != nil {
...
}