Swift3 optionals chaining in IF conditions bug? - swift

This code worked just fine in Swift 2.3 and I don't understand why I have to unwrap TestClass to check if number is bigger than 4. This is whole point of chaining optionals, to save additional call.
Now to make this work, I have to check if testClass != nil (or use implicit unwrap with if let statement) and then check count.
Is this really the only way?
import UIKit
class testClass
{
var optionalInt:Int?
}
var test:testClass?
if test?.optionalInt > 4
{
}

It's not a bug. It is, alas, intentional. Implicit unwrapping of optionals in comparisons (>) has been removed from the language.
So, the problem now is that what's on the left side of the > is an Optional, and you can no longer compare that directly to 4. You have to unwrap it and get an Int, one way or another.

First of all, where are you initialising your test var? Of course it'll be nil if you don't give it a value!
And regarding optional chaining, what's the issue writing :
if let optionalInt = test?.optionalInt, optionalInt > 4
{
}
As always, safety > brevity.

Optional comparison operators are removed from Swift 3.
SE-0121
You need to write something like this:
if test?.optionalInt ?? 0 > 4
{
}

This could also happen on Guard statement.
Example:
var playerLevels = ["Harry": 25, "Steve": 28, "Bob": 0]
for (playerName, playerLevel) in playerLevels {
guard playerLevels > 0 else {//ERROR !!
print("Player \(playerName) you need to do the tutorial again !")
continue
}
print("Player \(playerName) is at Level \(playerLevels)")
}

Related

Swift If program

Still a beginner with just playing around with some basic functions in swift.
Can someone tell me what is wrong with this code?
import UIKit
var guessInt: Int
var randomNum = arc4random_uniform(10)
if Int(randomNum) == guessInt {
println ("correct")
} else {
println; "no, the number is not. guess again"
}
So far the only error I'm getting is that
guessInt
is being used before being initialized!
I've tried to type everything again but still have the same error.
Thanks in advance.
In Swift you cannot read a value before it's set, which you're doing here:
if Int(randomNum) == guessInt
If you change your declaration from this:
var guessInt:Int
to this:
var guessInt = 6
then your code will work as expected (assuming you want the user's guess to be 6).
You've declared guessInt but now you need to initialize, or set it to some initial value.
For example:
let guessInt = 3
Another option is to declare guessInt as an "Optional", meaning that it can be nil, in fact it will be initialized to nil. This will print "no, ...." until you assign guessInit to a non nil value in the range of values produced by arc4random_uniform(10), but it will compile and run cleanly.
var guessInt:Int? // note the ? after Int this marks it as an Optional
var randomNum = arc4random_uniform(10)
if Int(randomNum) == guessInt {
println ("correct")
} else {
println; "no, the number is not. guess again"
}

Swift basic expression

I'm very new to swift, but proficient in other languages like Java, JavaScript, C, ... I'm lost with Swift syntax when it comes to create expressions. Look at this basic example where I just try to find out if one string is contained into another by calling String.rangeOfString that returns an Optional Range (Range?)
This works as expected:
let LEXEMA:String="http://"
let longUrl:String="http://badgirls.many/picture.png"
let range=longUrl.rangeOfString(LEXEMA);
if (range? != nil) {
// blah
}
Now I'm trying to combine the expression inside the if, something like:
if (longUrl.rangeOfString(LEXEMA)? !=nil) {
// blah
}
But I always get syntax errors, the above yields a "Expected Separator" and can't understand why. Done some more tests:
if (absolutePath.rangeOfString(URL_LEXEMA) !=nil) { }
Expected Separator before "!"
if absolutePath.rangeOfString(URL_LEXEMA) !=nil { }
Braced block of statements is an unused closure
What am I doing wrong?
If you’re coming from other like Java, you might be thinking of optionals like pointers/references, and so used to equating them to nil and if non-nil, using them. But this is probably going to lead to more confusion. Instead, think of them like a container for a possible result, that you need to unwrap to use. if let combines the test and unwrapping operation.
With this in mind, here’s how you could adapt your code:
let LEXEMA: String="http://"
let longUrl: String="http://badgirls.many/picture.png"
if let range = longUrl.rangeOfString(LEXEMA) {
// use range, which will be the unwrapped non-optional range
}
else {
// no such range, perhaps log an error if this shouldn’t happen
}
Note, that ? suffixing behaviour you were using changes in Swift 1.2 so even the code in your question that compiles in 1.1 won’t in 1.2.
It’s possible that sometimes you are whether there was a value returned, but you don’t actually need that value, just to know it wasn’t nil. In that case, you can compare the value to nil without the let:
if longUrl.rangeOfString(LEXEMA) != nil {
// there was a value, but you don't care what that value was
}
That said, the above is probably better expressed as:
if longUrl.hasPrefix(LEXEMA) { }
For starters:
You don't need parenthesis with if statements unless you have nested parenthetical subexpressions that require it.
You don't need to specify the type on the left side of the = of a let or var declaration if Swift can figure it out from the right side of the =. Very often Swift can figure it out, and you can tell that Swift can figure it out, so you can avoid that redundant clutter.
You do need to specify the type if Swift cannot figure out the type from
the right side. Example:
For example, consider the following lines:
let LEXEMA = "http://"
let longUrl = "http://badgirls.many/picture.png"
Swift can figure out that they're strings.
Similarly for this function or class that returns a UIView:
var myView = ViewReturningClassOrFunc()
Consider this:
#IBOutlet var myView : UIView!
In the above line, Swift cannot figure out ahead of time it will be assigned a UIView, so you have to provide the type. By providing a ! at the end you've made it an implicitly unwrapped optional. That means, like ?, you're indicating that it can be nil, but that you are confident it will never be nil at the time you access it, so Swift won't require you to put a ! after it when you reference it. That trick is a time saver and big convenience.
You should NOT add the ? to the line:
if (longUrl.rangeOfString(URL_LEXEMA) !=nil) {
As another answer pointed out, you're missing the let.
if let longUrl.rangeOfString(URL_LEXEMA) {
println("What do I win? :-)")
}
swift is case sensitive language. you need to check about whitespaces as well
if longUrl.rangeOfString(LEXEMA) != nil {
//your condition
}
there should be space between statement != nil
Just add a space between != and nil like:
if longUrl.rangeOfString(LEXEMA) != nil {
// blah
}
I tested your code in playground, an error of Expected ',' separator reported.
And do not forget the rules that 1s and 0s and Airspeed Velocity said.

Why there is a ? mark in if-let statement to see an optional has a value

I am reading the following book, on Page #32 there is a code snippet. December 2014: First Edition.
Swift Development with CocoaJonathon Manning, Paris Buttfield-Addison,
and Tim Nugent
I know we can use ? to make a vairbale optional and ! to unwrap a optional vairbale in Swift
var str: String? = "string"
if let theStr = str? {
println("\(theStr)")
} else {
println("nil")
}
Why do we need ? in this line if let theStr = str? It seems working just fine with out it and making no difference.
You don't need it, and shouldn't have it. The optional binding evaluates the optional. If it's nil, it stops. If it's not nil, it assigns the value to your required variable and then executes the code inside the braces of the if statement.
EDIT:
The language has changed slightly since it was first given out in beta form. My guess is that the ? used to be required.
Some of the sample projects I've used from Github fail to compile and I've had to edit them to get them to work. this might be an example where the syntax has changed slightly.
The current version of Swift does not require it, as it is redundant since your variable is already an optional.
Whatever you put in the if let statement does have to be an optional though or you will receive an error
Bound Value in a conditional binding must be of Optional type
Furthermore, if you are casting to a type, you do need to use as? to cast to an optional type.
var str2: Any = ["some", "example"]
if let theStr = str2 as? [String] {
println("\(theStr)")
} else {
println("nil")
}

Why are multiple unwrapping optionals impossible?

I've been playing with optionals in swift. I make frequent use of the conditional unwrap pattern:
var myOptional: AnyObject?
if let unwrapped = myOptional {
// do stuff
}
However, on occasion I have two optional values that I only want to use if both of them are non-nil. As such, I tried to use the following syntax:
var myOptional: AnyObject?
var myOtherOptional: AnyObject?
if let unwrapped = myOptional && let otherUnwrapped = myOtherOptional? {
// do stuff
}
I've tried putting the two parts in brackets etc. but there doesn't seem to be a way to do this. Is there a good reason why I shouldn't be able to do it? Obviously I can just embed one statement in the other but I would prefer to put it all on one line.
Starting with Swift 1.2 you can unwrap multiple optionals and conditions.
The “if let” construct has been expanded to allow testing multiple
optionals and guarding conditions in a single if (or while) statement
using syntax similar to generic constraints:
if let a = foo(), b = bar() where a < b,
let c = baz() { } This allows you to test multiple optionals and include intervening boolean conditions, without
introducing undesirable nesting (i.e., to avoid the “pyramid of
doom”).
Because the language doesn't support it.
In the document:
The value of any condition in an if statement must have a type that conforms to the BooleanType protocol. The condition can also be an optional binding declaration, as discussed in Optional Binding.
The condition must be an "expression of BooleanType" or an "optional binding declaration".
And "optional binding declaration" is not an "expression" so you can't join with &&.
Instead, you can do that with switch:
switch (myOptional, myOtherOptional) {
case let (.Some(unwrapped), .Some(otherUnwrapped)):
// do stuff
println("\(unwrapped), \(otherUnwrapped)")
default:
break
}
The only way is to nest if statements. I think this is because apple implemented it as syntactic sugar. So the pre compiler converts
var myOptional: AnyObject?
if let unwrapped = myOptional {
// do stuff
}
into
var myOptional: AnyObject?
if myOptional != nil {
let unwrapped = myOptional
// do stuff
}
You can of course do this by yourself in a single if, but this will make your code only a little prettier. On the downside, you won't know which one caused the crash while debugging.
For more information see the documentation
var myOptional: AnyObject?
var myOtherOptional: AnyObject?
let unwrapped: AnyObject? = myOptional, otherUnwrapped: AnyObject? = myOtherOptional?
if (unwrapped != nil && otherUnwrapped != nil) {
// Do Stuff
}
This is another way you could do it. Swift is looking better day by day

How to and Where to use "?" and "!" in Swift

I didn't find any much difference while using ? and ! in Swift. Here is the some example code of when I use ?
var myString:String? = "Ganesh";
if myString{
println(myString)
}else{
println(myString)
}
OutPut was: Optional Ganesh
var myString:String? = "Ganesh";
myString = nil
if myString{
println(myString)
}else{
println(myString)
}
OutPut was: nil
and when I use !
var myString:String! = "Ganesh";
if myString{
println(myString)
}else{
println(myString)
}
OutPut was: Ganesh
var myString:String! = "Ganesh";
myString = nil
if myString{
println(myString)
}else{
println(myString)
}
OutPut was: nil
Can someone please help me to get brief on it? Thanks in advance
First, the technical difference:
When you use var y : String?, you have to use if let x = y { /* do something with x */ } or y! to be able to use the value inside y. y.toInt() will not work, because toInt() does not exist on Optional<String>.
When you use var y : String!, you are using an implicitly unwrapped optional. When you do y.toInt(), it will behave as if you had said y!.toInt(). This is the entire difference.
Now, usage:
If at all possible, use variables, return values or properties that aren't optionals at all.
If you must have optionals, if possible, use ? (ordinary optionals). This clearly signals that the optional may not have a value and that it is as a consequence of the design.
When the implicitly unwrapped optional - ! - is used, it shows that it is "probably" supposed to have a value, and it is usually used when the information about whether it should be optional or not simply is not available, like Objective-C frameworks. This makes working with values that nearly always have a value easier (because you don't have to type ! all the time), but it also means that they encourage code that don't check for nil and that may therefore crash and burn.
Apple uses the implicitly unwrapped optional when importing Cocoa frameworks, but they are also cleaning up a lot of their own frameworks to use ordinary ? optionals or non-optionals instead of implicitly unwrapped optionals, since that provides a lot more information about what to expect.
(Update 2014-09-30: I had completely mixed up the advice for "!" and "?" - "?" is meant to be preferred over "!". I have edited the answer.)