hasPrefix misbehave on Optional String - swift

Why does the following always print "prefix" which is incorrect but print "no prefix" when String is not optional or implicitly unwrapped optional?
var value:String! = "aaa" // Same incorrect behavior on Optional String as well.
if value?.hasPrefix("bbb") {
NSLog("prefix")
}
else {
NSLog("no prefix")
}

The if statement is checking if the statement returns a value or nil, not if it returns true or false. You can use another if statement to check the value of hasPrefix().
var value:String! = "aaa" // Same incorrect behavior on Optional String as well.
if let hasPrefix = value?.hasPrefix("bbb") {
if hasPrefix{
NSLog("prefix")
}
else {
NSLog("no prefix")
}
}
else {
NSLog("nil value")
}

This is related (not sure if duplicate) of: How to check if Optional is not nil and property is true in one expression?
Summarizing it a bit for your question:
When you use Optional Chaining, the returned value is always an Optional. That means value?.hasPrefix("bbb") returns Bool? and not Bool. Thus, if value is not nil, value?.hasPrefix("bbb") will always not be nil, and so it will go into the first case, no matter if its true or false.
This is explained in the Swift book section on Optional Chaining. It makes sense because when you use Optional Chaining, the return value always has a chance to return nil, and that doesn't depend on the final value in the "chain".

You if statement just gives you an optional result because you are calling the "hasPrefix()" on an optional value.
This wouldn't even work in the newer versions of swift and would give the error :
Value of optional type 'Bool?' not unwrapped; did you mean to use '!'
or '?'?
Refer this for documentation on the same.
Following would give you the required result:
if let val = value, val.hasPrefix("bbb") {
NSLog("prefix")
} else {
NSLog("no prefix")
}

Related

how to set optional parameter in function on Swift [duplicate]

When I set firstThing to default nil this will work, without the default value of nil I get a error that there is a missing parameter when calling the function.
By typing Int? I thought it made it optional with a default value of nil, am I right? And if so, why doesn't it work without the = nil?
func test(firstThing: Int? = nil) {
if firstThing != nil {
print(firstThing!)
}
print("done")
}
test()
Optionals and default parameters are two different things.
An Optional is a variable that can be nil, that's it.
Default parameters use a default value when you omit that parameter, this default value is specified like this: func test(param: Int = 0)
If you specify a parameter that is an optional, you have to provide it, even if the value you want to pass is nil. If your function looks like this func test(param: Int?), you can't call it like this test(). Even though the parameter is optional, it doesn't have a default value.
You can also combine the two and have a parameter that takes an optional where nil is the default value, like this: func test(param: Int? = nil).
The default argument allows you to call the function without passing an argument. If you don't pass the argument, then the default argument is supplied. So using your code, this...
test()
...is exactly the same as this:
test(nil)
If you leave out the default argument like this...
func test(firstThing: Int?) {
if firstThing != nil {
print(firstThing!)
}
print("done")
}
...then you can no longer do this...
test()
If you do, you will get the "missing argument" error that you described. You must pass an argument every time, even if that argument is just nil:
test(nil) // this works
Swift is not like languages like JavaScript, where you can call a function without passing the parameters and it will still be called. So to call a function in Swift, you need to assign a value to its parameters.
Default values for parameters allow you to assign a value without specifying it when calling the function. That's why test() works when you specify a default value on test's declaration.
If you don't include that default value, you need to provide the value on the call: test(nil).
Also, and not directly related to this question, but probably worth to note, you are using the "C++" way of dealing with possibly null pointers, for dealing with possible nil optionals in Swift. The following code is safer (specially in multithreading software), and it allows you to avoid the forced unwrapping of the optional:
func test(firstThing: Int? = nil) {
if let firstThing = firstThing {
print(firstThing)
}
print("done")
}
test()
You are conflating Optional with having a default. An Optional accepts either a value or nil. Having a default permits the argument to be omitted in calling the function. An argument can have a default value with or without being of Optional type.
func someFunc(param1: String?,
param2: String = "default value",
param3: String? = "also has default value") {
print("param1 = \(param1)")
print("param2 = \(param2)")
print("param3 = \(param3)")
}
Example calls with output:
someFunc(param1: nil, param2: "specific value", param3: "also specific value")
param1 = nil
param2 = specific value
param3 = Optional("also specific value")
someFunc(param1: "has a value")
param1 = Optional("has a value")
param2 = default value
param3 = Optional("also has default value")
someFunc(param1: nil, param3: nil)
param1 = nil
param2 = default value
param3 = nil
To summarize:
Type with ? (e.g. String?) is an Optional may be nil or may contain an instance of
Type
Argument with default value may be omitted from a call to
function and the default value will be used
If both Optional and has default, then it may be omitted from function call OR may be included and can be provided with a nil value (e.g. param1: nil)
in case you need to use a bool param, you need just to assign the default value.
func test(WithFlag flag: Bool = false){.....}
then you can use without or with the param:
test() //here flag automatically has the default value: false
test(WithFlag: true) //here flag has the value: true
"Optional parameter" means "type of this parameter is optional". It does not mean "This parameter is optional and, therefore, can be ignored when you call the function".
The term "optional parameter" appears to be confusing. To clarify, it's more accurate to say "optional type parameter" instead of "optional parameter" as the word "optional" here is only meant to describe the type of parameter value and nothing else.
If you want to be able to call the func with or without the parameter you can create a second func of the same name which calls the other.
func test(firstThing: Int?) {
if firstThing != nil {
print(firstThing!)
}
print("done")
}
func test() {
test(firstThing: nil)
}
now you can call a function named test without or without the parameter.
// both work
test()
test(firstThing: 5)
Don't let the question mark fools you!
Optional is an enum which has two cases:
#frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
///
/// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
}
code from the original compiled source of the Optional inside Xcode
When you are defining a function that accept some Type of arguments, you can pass a default value withe the same type.
in your case
the type of the firstThing is Optional<Int> (also known as Int?). So if you want the caller to the oportunity to ignore the paramter, you MUST do the job for the caller and pass a default value.
Usually we need the .none case of the optional so we can do:
func test(firstThing: Optional<Int> = .none) { ... }
This is exactly the same as:
func test(firstThing: Int? = nil) { ... }
Also!
Who seys that we the default value of an optional is a nil? maybe passing nil means that the function should remove something by updating it's value to 'nil'. So don't asume "the default value for optional is a nil"
It is little tricky when you try to combine optional parameter and default value for that parameter. Like this,
func test(param: Int? = nil)
These two are completely opposite ideas. When you have an optional type parameter but you also provide default value to it, it is no more an optional type now since it has a default value. Even if the default is nil, swift simply removes the optional binding without checking what the default value is.
So it is always better not to use nil as default value.
Default value doesn't mean default value of data type .Here default value mean value defined at the time of defining function.
we have to declare default value of variable while defining variable in function.

Initializer for conditional binding must have Optional type, not 'String' not working after clean build

swift code is not working after clean build.
how can i rewrite this simple code?
if let name: String = String(cString: (interface?.ifa_name)!), name == "utun0" {
print("Ipfound")
ipFound = true;
}
i put image for better understanding.
The if let construct is used for "conditional binding" of an optional. The thing you are trying to assign to name (the function result) is not optional - instead, the value you are passing to String(cString:,name:) is optional.
You should rewrite your code to something like this:
if let interfaceName = interface?.ifa_name {
let name = String(cString: interfaceName)
if name == "utun0" {
print("Ipfound")
ipFound = true
} else {
print("name != Ipfound")
}
} else {
print("interface or interface.ifa_name is nil")
}
In that code I'm using optional binding to try to get a non-nil value from interface?.ifa_name.
If you use ! "force unwrap" operator as you were trying to do, your code would crash if interface is nil, or if interface.ifa_name is nil.
Edit:
Another way you could handle this, that would look closer to your original code, would be to use map() on the Optional:
if let name: String = interface?.ifa_name.map ({ String(cString: $0)}),
name == "utun0" }
{
print("Ipfound")
ipFound = true;
}
The form of map() that works on an Optional takes an Optional as input. If that optional is nil, it returns nil. If the optional is not nil, the result returned by map() is the result of applying your closure to the unwrapped optional.

"Value of optional type 'Set<String>?' must be unwrapped", but I didn't ask for an optional

Xcode complains "Value of optional type 'Set?' must be unwrapped to refer to member 'contains' of wrapped base type 'Set'"
Here's the function:
func talks_to (_ dialog_dict: Dictionary<String, Set<String>>, one: String, two: String) -> Bool {
return dialog_dict[one].contains(two)
}
This is a nested function, meant only to make logic clearer, and the parameters are guaranteed to be non-nil by the outer code. How do I get swift to understand this?
Any time you fetch an item from a dictionary using subscripting, the result is an Optional because the key you use might not be found. Sh_Khan gave you a nice elegant solution: (voted)
return dialog_dict[one]?.contains(two) == true
That works because nil does not equal true, but the compiler will unwrap it and check the value inside to see if it equals true if it's not nil. So if the result of dialog_dict[one] is nil or false, it does not equal true. Only if dialog_dict contains a value for the key one and that value is true does the expression return true.
Make it
return dialog_dict[one]?.contains(two) == true
or
return dialog_dict[one]!.contains(two)
this dialog_dict[one] returns optional

How to check if a variable is nil

I have a variable
var a: [AnyObject? -> Void]
and I am adding data in to it by append method. Now I want to check if the variable is nil or not. I tried using [] but not working and also tried "", this also not working, can anyone tell what is the meaning of this variable and how to check if it is nil.
As far as I understand, var a is an Array of functions that take an optional Object of any type, and return void. So these functions's parameter IS optional, but the Array itself isn't : it cannot be nil, or it would be declared [AnyObject? -> Void]? , no?
EDIT : if, nevertheless, you declared this a as an optional (but WHY would you do that ?) - adding a ? - you check an optional existence with if let :
if let b = a {
// a not nil, do some stuff
} else {
// a is null
}
If you just want to check if the array is empty, use isEmpty method from Swift Array
Update: Xcode 7.3 Swift 2.2
If you want to check if a variable is nil you should use if let to unwrap if for you. There is no need to create a second var.
let str = "123"
var a = Int(str)
if let a = a {
print(a)
}
Or
if let a = Int(str) {
print(a)
}
In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types.
So, You can check it with below code:
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
if convertedNumber != nil {
println("convertedNumber contains some integer value.")
}
// prints "convertedNumber contains some integer value."
Please refer this about nil for more information.
In Swift 3.0
if let imageURL = dictObj["list_image"] as? String {
print(imageURL)
}
You can use if let. if let is a special structure in Swift that allows you to check if an Optional holds a value, and in case it does – do something with the unwrapped value.
var a:Int=0
if let b=a{
println(a)
} else {
println("Value - nil")
}
But for Strings you can also use .isEmpty() If you have initialized it to "".
var str:String=""
if !str.isEmpty(){
println(str)
}
For me none of the above solutions worked when I was using an AVFoundation object.
I would get Type 'AVCaptureDeviceInput does not conform to protocol 'BooleanType' when I tried if (audioDeviceInput) and I would get Binary operator '!=' cannot be applied to operands of type 'AVCaptureDeviceInput' and 'nil'.
Solution in my situation
if (audioDeviceInput.isEqual(nil))
nil is a pointer like any other and can be referenced as such, which is why this works.

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!)