Swift error: Int is not convertible to 'DictionaryIndex<Int,Int>' - swift

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

Related

Assigning to an optional variable in swift 3.0 using ? operator returns nil

Consider the following code.
var a:Int?
a? = 10
print(a)
Here the variable a isn't getting assigned the value 10. If it is because of the '?' operator, why compiler doesn't show a compilation error?.
Try this
var a:Int?
a = 10
print(a)
Well...
? (Optional) indicates your variable may contain a nil value while ! (unwrapper) indicates your variable must have a memory (or value) when it is used (tried to get a value from it) at runtime.
The main difference is that optional chaining fails gracefully when the optional is nil, whereas forced unwrapping triggers a runtime error when the optional is nil.
var defaultNil : Int? // declared variable with default nil value
println(defaultNil) >> nil
var canBeNil : Int? = 4
println(canBeNil) >> optional(4)
canBeNil = nil
println(canBeNil) >> nil
println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper
var canNotBeNil : Int! = 4
print(canNotBeNil) >> 4
var cantBeNil : Int = 4
cantBeNil = nil // can't do this as it's not optional and show a compile time error
Here is basic tutorial in detail, by Apple Developer Committee.

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 {
...
}

Swift: logical not operator not working

this piece of code prints two times 'false':
println(levelController?.died)
println(!levelController?.died)
I don't understand why, the levelController is instantiated and the died attribute is declared in LevelController like this:
var died = false
Can someone tell me what I might be doing wrong?
You can create your own not operator like this:
let not = (!)
And now we can assign a bool to test this:
let dead = false
if not(dead) {
print(dead)
// Code
} else {
// Code
}
This is Swift, not Objective C.
levelController?.died is not a boolean value. It is an optional boolean. It can be true, false, or nil. The first println prints false. The logical not operator, applied to an optional, returns false if the optional is not nil, and true if the optional is nil. Just as it does in C when applied to a pointer.
As a complete example, your code:
class Controller {
var died: Bool = false
}
var levelController: Controller? = Controller()
println(levelController?.died)
println(!levelController?.died)
Outputs the following:
Optional(false)
false
The first version of your code levelController?.died makes use of option chaining, unwrapping the levelController and accessing the died property. This explains why the output is Optional(false). You would typically use it as follows:
if let died = levelController?.died {
if (died) {
println("I died")
}
}
The if-let statements unwraps this optional value.
The second version of your code !levelController?.died tests whether the given optional value is nil or not. You will notice that changing died to true of false makes no difference.
However, changing the instantiation as follows:
var levelController: Controller? = nil
Results in !levelController?.died becoming true. This isn't really a terribly practical piece of code!

The implicit unwrapping of an optional boolean

The implicit unwrapping of a Bool type does not seem to work:
var aBoolean: Bool! // nil
aBoolean = false // false
aBoolean // false
aBoolean == true // false
aBoolean == false // true
if aBoolean {
"Hum..." // "Hum..."
} else {
"Normal"
}
if aBoolean! {
"Hum..."
} else {
"Normal" // "Normal"
}
If I had declared aBoolean like var aBoolean: Bool?, this would have been the expected behavior but here, I don't get it.
Is this the correct behavior? I didn't find any doc about it.
Thanks!
The first test is checking whether aBoolean stores a value rather than nil, which it does:
if aBoolean {
"Hum..." // "Hum..."
else {
"Normal"
}
The second test is checking against the actual boolean value stored in aBoolean, which is false:
if aBoolean! {
"Hum..."
} else {
"Normal" // "Normal"
}
This is Illustrated in the Swift book in the "Implicitly Wrapped Optionals" section. I think the implicit unwrapping just doesn't apply with if-statements. I agree it is strange but here is the Apple example:
You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value:
let assumedString: String! = "An implicitly unwrapped optional string."
if assumedString {
println(assumedString)
}
// prints "An implicitly unwrapped optional string."
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/us/jEUH0.l
Not an answer, but if this is indeed the intended behavior with implicitly unwrapped booleans it's rather disturbing. As soon as you use the expression in any logic proposition it will get unwrapped:
var aBoolean: Bool! = false
if !aBoolean {
"I'm unwrapping" // "I'm unwrapping"
}
if aBoolean == false {
"I'm unwrapping" // "I'm unwrapping"
}
Say you have this in your code an at some point your model changes and the condition is reversed, you delete the NOT.
if aBoolean {
"I'm unwrapping" // <- ouch
}
You just got screwed. Makes me want to avoid the implicit unwrapping.
You are making two different truth-checks.
Given:
var aBoolean: Bool! // nil
aBoolean = false // false
if aBoolean {
"Hum..." // "Hum..."
else {
"Normal"
}
if aBoolean! {
"Hum..."
} else {
"Normal" // "Normal"
}
...in the first if aBoolean, the value is not being unwrapped, it is simply testing the optional type to determine if it stores a value.
In the second if aBoolean!, you are testing the truth-value of the unwrapped Bool.
To see that it is indeed being implicitly-unwrapped (when not used in a conditional), try:
println("value of implicitly-unwrapped aBoolean: \(aBoolean)")
...this will print 'true' when aBoolean is set to true, 'false' when it is set to false, and 'nil' when it has not yet been assigned.
Here is the behavior clearly shown:
> var bool1 : Bool!
bool1: Bool! = nil
> bool1 = false
> (bool1 ? "yes" : "no")
$R19: (String) = "yes"
In the above, since bool1 is an optional (which becomes a Some instance), the conditional of simply bool1 evaluates to true (it is not nil).
> var bool2 : Bool = false
bool2: Bool = false
> (bool2 ? "yes" : "no")
$R25: (String) = "no"
When bool2 is not an optional, the conditional of simply bool2 evaluates to false (the value of bool2)
When declaring a variable as "implicitly unwrapped", using the !, it is still an Optional
This type of variable behaves very much like the standard variable type in Objective-C. It can be assigned to nil, but when you access members you do not need to explicitly unwrap it. In this way it is "unsafe" just like in ObjC because you can be accessing properties from nil
Thus, it is used most commonly when bridging from Objective-C. However, it is still an optional, with the only difference being you don't need to unwrap it to access the contents.
I believe this was added mostly to support interop between Swift and Obj-C and might be good practice to sparingly use it in pure Swift code. (Swift guidelines are a fuzzy thing right now and someone might prove me wrong soon!)