I was trying to get Boolean data with readLine()! but cannot input it
There was a compilation error saying
error: cannot convert value of type 'String' to specified type 'Bool'
readLine() returns a String?. You cannot implicitly convert a String to Bool.
Swift does not know what strings you consider to be a valid boolean value. Are 0 and 1 considered boolean values by your app? no and yes? falsch and wahr? Swift does not know. You need to parse it yourself, for example:
let myBool: Bool
switch stringInput.lowercased() {
case "false", "no", "0": myBool = false
case "true", "yes", "1": myBool = true
default:
print("Invalid input")
return
}
print(myBool)
Related
This question already has answers here:
Swift optionals - warning on conditional cast from 'x' to 'x' always succeeds
(2 answers)
If let clause when getting from NSUserDefaults()
(2 answers)
Closed 5 years ago.
if let seen: Bool = defaults.bool(forKey: UtilitiesKeys.mainTutorialSeen) {
return seen
}
return false
if i do this swift shows me an issue:
Conditional cast from 'Bool' to 'Bool' always succeeds, Non-optional
expression of type 'Bool' used in a check for optionals.
Since there might not be a value for my key, I don't want to force unwrap it. Now obviously it's working like this, but how do I safely unwrap the value without having swift complaining?
I have tried to use guard as well...
if let seen = UserDefaults.standard.object(forKey: UtilitiesKeys.mainTutorialSeen)) as? Bool {
return seen
}else {
return false
}
Apple document says:
/*!
-boolForKey: is equivalent to -objectForKey:, except that it converts the returned value to a BOOL. If the value is an NSNumber, NO
will be returned if the value is 0, YES otherwise. If the value is an
NSString, values of "YES" or "1" will return YES, and values of "NO",
"0", or any other string will return NO. If the value is absent or
can't be converted to a BOOL, NO will be returned.
open func bool(forKey defaultName: String) -> Bool
Initializer for conditional binding must have Optional type, not 'Bool'
hope this help you.
As suggested in doc:
-boolForKey: is equivalent to -objectForKey:, except that it converts the returned value to a BOOL. If the value is an NSNumber, NO will be returned if the value is 0, YES otherwise. If the value is an NSString, values of "YES" or "1" will return YES, and values of "NO", "0", or any other string will return NO. If the value is absent or can't be converted to a BOOL, NO will be returned.
open func bool(forKey defaultName: String) -> Bool
It is not an optional anymore. So you don't need to cast it with if let.
You can directly use:
let seen = defaults.bool(forKey: UtilitiesKeys.mainTutorialSeen)
I am trying to check if the string is empty of not, if it is not empty, i want to display the at the textField (outUrl.text)
let storage = UserDefaults.standard
var mainsite = storage.object(forKey:"sitestring") ?? ""
if (mainsite != "") {
outUrl.text = mainsite
}
But I have error:
Error: != cannot be applied to operands of type string and any
How do i check if the string is not empty?
The recommended solution is to use the appropriate API (string(forKey:) which returns String rather than Any and optional bindings.
The benefit is you get rid of any type cast and the nil coalescing operator
if let mainsite = UserDefaults.standard.string(forKey:"sitestring"), !mainsite.isEmpty {
outUrl.text = mainsite
}
The result returned by the Objective-C API -[UserDefaults obejectForKey:] is of type id, in order to accomodate various types of objects (NSString, NSNumber, etc, etc.). When accessed form Swift code, this becomes Any? (any type, perhaps nil).
If you know the stored value is indeed a string, you need to attempt cast it before comparing: != between values of types String and Any? isn't defined by default! What meaning would that have?):
var mainsite = storage.object(forKey:"sitestring") as? String ?? ""
This way, you either get a String value (if the cast succeeds) or the empty string (if it fails, because either there is no object for key "sitestring" or it isn't convertible to a String value).
The result from UserDefaults.standard is of type Any?, so before assigning the value to mainsite variable, typecast it to String. Here is an example,
let storage = UserDefaults.standard
var mainsite = storage.object(forKey:"sitestring") as? String
I'm new to Swift and is trying to learn the concept of optional values. My question is, within the context of the code before, is necessary to set variable 'possibleIntegerValue' to 'optional Int(Int?)' or it is ok to omit the ? sign and set 'possibleIntegerValue' to the type 'Int' instead?
What kind of impact doesit make if I indeed change the type from optional Int to Int?
let numberSymbol: Character = "三" // Simplified Chinese for the number 3
var possibleIntegerValue: Int?
switch numberSymbol {
case "1", "١", "一", "๑":
possibleIntegerValue = 1
case "2", "٢", "二", "๒":
possibleIntegerValue = 2
case "3", "٣", "三", "๓":
possibleIntegerValue = 3
case "4", "٤", "四", "๔":
possibleIntegerValue = 4
default:
break
}
if let integerValue = possibleIntegerValue {
print("The integer value of \(numberSymbol) is \(integerValue).")
} else {
print("An integer value could not be found for \(numberSymbol).")
}
Optionals allow you to have a case where there is no value. You have the following options for declaring a variable:
var possibleIntegerValue: Int? // Optional Int
var possibleIntegerValue: Int = 0 // Not optional but must *always* have a value
var possibleIntegerValue: Int! // Implicitly unwrapped Optional Int
In the third option above, you are guaranteeing that possibleIntegerValue will have a value by the time it is first used (or your app will crash with an uncaught exception).
Since your switch statement has a default that does not give possibleIntegerValue a value, using an Optional Int seems appropriate.
I would like to check the type of a dictionary value, and I use the following test code:
let swiftDict = [1: "one", 2: "two"]
if swiftDict[1] is NSString {
println("it's an nsstring")
}
I got Compiler warning: "Cast from 'String?' to unrelated NSString always fails.
Modified the code to the following:
if let str = swiftDict[1] as? NSString? {
println("it's an nsstring")
}
Now I get Compiler warning: Conditional cast from String? to NSString? always succeeds.
How do I fix the above warning? What's the right way to check for a variable type?
The reason for the check is to find out whether String or NSString is stored.
If you have a dictionary with mixed types (i.e. value:AnyObject) you could iterate through them and use is to check what type a value in the dictionary is, e.g.
let swiftDict:[Int:AnyObject] = [1: "one", 2: "two", 3: 15, 4: true]
for (key, value) in swiftDict
{
if (value is String)
{
println("\(key): \(value) is String")
}
}
Why do you want to test your value type at all, as Swift is already type-safe?
Contrary to Objective-C, arrays and dictionaries in Swift are typed. So your swiftDict variable is of type Dictionary<Int, String> (or [Int:String] for short) and thus the values of this dictionary will always be Strings, by definition.
For example, if you had tried to write this:
let swiftDict = [1: "one", 2: "two", 3: 7]
// error: '_' is not convertible to 'StringLiteralConvertible'
Then the compiler would error, telling you that 7 is not of type String nor convertible to a String, so you can't add it to swiftDict, which is inferred to be of type [Int:String]
This means that, by definition, swiftDict[1] will always be a String (because swiftDict is a [Int:String])… or nil if there is no key 1 in that dict.
--> swiftDict[1] is guaranteed to be of type String?. So you don't even need to test the type cast. You just need to test if it's nil or not.
if let value = swiftDict[1] {
println("swiftDict has a string value of \(value) for key 1")
} else {
println("swiftDict does not have the key 1")
}
[EDIT] Also note that String and NSString are toll-free bridged, which means that they are totally interchangeable. So you don't even need to test or cast if your String is an NSString, as it will always be possible to cast from String to NSString and vice-versa (it will always be possible to interpret your string either as String or NSString).
guard could be used
guard let key = swiftDict[1] else {
println("swiftDict does not have the key 1")
return;
}
It wont matter if you cast it to string or NSString as its just a character sequence in the dictionary. Both will work. If it's a string in the dictionary, it's a String or an NSString, depending what you set it as.
if let str = swiftDict[1] as? String
{
println("it's a string")
}
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")
}