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).
Related
I've read Non-optional shown as optional on print but that doesn't help my question.
I'm returning a Integer, but once it's printing it's being printed as optional. Why?
I'm trying to solve a code challenge. The goal is to:
Write an extension for collections of integers that returns the number
of times a specific digit appears in any of its numbers.
Here is my implementation:
extension Collection where Iterator.Element == Int {
func challenge37(count character : Character) -> Int?{
guard nil != Int(String(character)) else{
print("character wasn't an integer")
return nil
}
var counts : [Int] = []
for item in self{
var counter = 0
let stringInt = String(describing: item)
for currentCharacter in stringInt.characters{
if character == currentCharacter{
counter += 1
}
}
counts.append(counter)
}
guard let min = counts.min() else{
print("no min")
return nil
}
return min
}
}
As you can see here I'm printing it:
print([5,15,512,522].challenge37(count: "5")) // Optional(1)
Inside the function your returning an Int. However the actual signature of your method is Int? meaning it is in fact an optional and you got it wrong!
Basically your method signature is correct. But when you call the function you're getting an optional as the response and must unwrap it.
print([5,15,512,522].challenge37(count: "5")!) // 1
Additionally had you paid close attention you would have noticed that Xcode must gave you a warning (and solutions to solve it)
Expression implicitly coerced from Int? to Any
Xcode gave you the warning because it found out that you're attempting to print an optional and knows that's usually unwanted. Obviously its solution is to unwrap it either through force unwrap or defaulting.
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() {
}
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")
}
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 {
...
}
When I switched over from Xcode 6 beta 4 to beta 5 I got this error (Int is not convertible to 'DictionaryIndex') in reference to my plays variable. I don't know how to remedy this.
Here is the code block:
var plays = Dictionary<Int,Int>()
var done = false
var aiDeciding = false
//Function that says what to do if a UIButton is clicked:
#IBAction func UIbuttonClicked(sender:UIButton) {
if !plays[sender.tag] && !aiDeciding && !done {
setImgforCircle(sender.tag, player:1)
thinkingLabel.hidden = true
thinkingLabel2.hidden = true
thinkingLabel3.hidden = true
}
I suppose this is just a deceiving error message and the actual error is in
if !plays[sender.tag]
Instead, it should be
if plays[sender.tag] != nil
This is due to a change in the language, specifically this
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.
plays[sender.tag] returns an Option<Int> and you are assuming that a nil value will evaluate to false, hence !plays[sender.tag].
Since beta 5 this is forbidden and you have to explicitly check against nil
plays[sender.tag] != nil