I am very confused with unwrap fundamentals of Swift 2.0. I have bellow code to display last name string value from dictionary to label.
let lastName:String? = self.userDict.objectForKey("last_name")
self.lblLastName.text = "Last Name: " + lastName!
but some times this code run before value assign in to self.userDict at that time above code get self.userDict.objectForKey("last_name") nil and throw an error.
For solution i modified my code like bellow and keep that value unwrap but compiler don't take it as valid
let lastName:String? = self.userDict.objectForKey("last_name")
self.lblLastName.text = "Last Name: " + lastName? //--ERROR: Value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?
Please suggest me valid way to fulfil the requirement.
You need to provide a way to handle cases when dictionary has no value for key "last_name" and returns nil. Easiest way is to use nil coalescing operator ??:
The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.
You could do something like:
let lastName: String = self.userDict.objectForKey("last_name") ?? "N/A"
self.lblLastName.text = "Last Name: " + lastName
You could also use Optional Binding to check if the retrieved value from dictionary is nil or not. Then you can assign the string to your label (lblLastName) conditionally.
if let lastName = self.userDict.objectForKey("last_name") {
self.lblLastName.text = "Last Name: " + lastName
} else {
self.lblLastName.text = "Last Name: " + "some other hard coded string"
}
Related
let say I defined a class
class Dummy {
var title: String?
}
and I have a dictionary as
let foo: [Int: String?] = [:]
then when I make an assignment as below
var dummy = Dummy()
dummy.title = foo[1]
it says
Cannot assign value of type 'String??' to type 'String?'
Insert ' as! String'
return type of foo is String? and Dictionary returns optional of its value type when used subscript but what is String?? type in swift?
I think it should be legal to make such assignment.
Why it complains and how should I make this assignment
Since having a value corresponding to the key 1 in the dictionary foo is optional and the value in the dictionary is of type String? it returns type String??. Unwrapping the value once to check if the value exists would fix this issue
if let value = foo[1] {
dummy.title = value
}
By declaring your dictionary as [Int:String?] you are saying that the key is an Int and values are optional Strings. Now the key may not be present in the dictionary, so foo[1] optionally returns an optional and you end up with an with an optional optional - String??
Now while there are sometimes uses for optional optionals, I don't think that is what you want in this case.
You can simply make a dictionary of [Int:String] and then not insert an element if the value is nil.
let foo: [Int: String] = [:]
dummy.title = foo[1]
If you do need to handle the case where "there is a value for this key and it is nil" then the nil-coalescing operator may help you:
dummy.title = foo[1] ?? nil
or even
dummy.title = foo[1] ?? ""
I need to save the changing text of my label as a variable, but if write the following code:
var warn = Int(self.dyn.text)
It says:
Value of optional type 'String?' must be unwrapped to a value of type 'String'
Coalesce using '??' to provide a default when the optional value contains 'nil'
Force-unwrap using '!' to abort execution if the optional value contains 'nil'
What code should I use?
var warn = Int(self.dyn.text ?? "") ?? 0
You have to provide a default value, just in case it's not possible to make the cast to Int. You also have to make sure the text value is not nil.
Take a look at optional chaining and optional binding
Another approach is:
if let dynText = self.dyn.text {
if let warn = Int(dynText) {
// warn is an available int variable here.
}
}
2 way of doiing that
1: let warn = Int(self.dyn.text ?? "") ?? 0
2: let warn = Int(self.dyn.text!)!
Good. Because String can be "123" or "Hello,world" so it can be numeric or String text
When you use this
Int(String) the initializer might fail, it returns an optional Int, rather than an Int
Example
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"
So you have to Unwrap it
Like that
// unwrap text if TextField is not `!` and then unwrap text when you convert to Int
if let dynText = self.dyn.text , let warn = Int(dynText) {
print(warn)
}
I have created my own class in Swift as below.
class Product: NSObject {
var product_id:Int?
var product_number:String?
var product_price:Float?
var product_descrption:String?
}
Now i am setting value in each property like this
let p=Product()
p.product_id=1
p.product_price=220.22
p.productdescrption="Some description"
p.product_number="W2_23_233"
But when i get the value from price then for price i get value like "Optional 220.22" But i don't get appended word "Optional" in description".So to resolve this i added "!" for unwrapping the value of float but i did not have to do this for String please tell why this is happening?
If you are printing any of these values should say Optional(...). If you are assigning the values to a label, that will not include the Optional(...), The reason that it shows Optional(...) when you print the value using print(), is just to show you its an optional. For safety, instead of using the !, try using if lets.
An example with your code,
if let id = p.product_id {
print(id) //Does not contain Optional()
}
You can also combine them, to do them all at one time. (Only do this if you don't want to print unless all values are non-nil)
if let id = p.product_id,
let price = p.product_price,
let description = p.productdescrption,
let productNumber = p.product_number {
//Enter code here that does something with these values
}
Note, if you aren't on swift 3, I believe you only have to write let on the first condition.
If you print any optional variable without unwrapping no matter what type it is, Optional will be appended to the variable's value.
print(p.product_price) will print Optional(220.220001)
print(p.product_descrption) will print Optional("Some description")
To print only value you need to unwrap the optional variables.
print(p.product_price!) will print 220.22
print(p.product_descrption!) will print Some description
This forced unwrapping will only work if the optionals does not contain nil. Otherwise it will give you a runtime error.
So to check for nil you can use if let statement.
No matter what type of variable. If you assign a value to an optional variable, It always enclosed with Optional(...)
Optional without forced unwrapping:
print("product_price = \(p.product_price) \n product_descrption = \(p.product_descrption)")
Output:
product_price = Optional(220.22)
product_descrption = Optional(Some description)
Optional with forced unwrapping:
print("product_price = \(p.product_price!) \n product_descrption = \(p.product_descrption!)")
Output:
product_price = 220.22
product_descrption = Some description
I want to take out a part of my String and afterwords I want to save it in a new String.
var key = "Optional("rFchd9DqwE")"
So my String equals now to Optional("rFchd9DqwE"). Now I want to take out the part rFchd9DqwE from this String and save it back in the variable "key". Is there a simple way to do this?
If you have code like this:
var aString: String? = "rFchd9DqwE"
let b = "\(aString)"
Then the problem is that you are doing it wrong. The "Optional()" bit in your output is telling you that you passed in an optional type instead of a string type.
What you should do is something like this instead:
var aString: String? = "rFchd9DqwE"
if let requiredString = aString
{
let b = "\(requiredString)"
}
the "if let" part is called "optional binding". It converts aString from an optional to a regular String object and saves the result in the new constant requiredString. If aString contains a nil, the code inside the braces is skipped.
Another way to do this would be to use the nil coalescing operator:
var aString: String? = "rFchd9DqwE"
let b = "\(aString ?? "")"
The construct aString ?? "" returns the string value of aString if it's not nil, or replaces it with the value after the ?? if it is nil. In this case it replaces nil with a blank.
While reading the The Swift Programming Language, I came across this snippet:
You can use if and let together to work with values that might be
missing. These values are represented as optionals. An optional value
either contains a value or contains nil to indicate that the value is
missing. Write a question mark (?) after the type of a value to mark
the value as optional.
// Snippet #1
var optionalString: String? = "Hello"
optionalString == nil
// Snippet #2
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
Snippet #1 is clear enough, but what is happening in the Snippet #2? Can someone break it down and explain? Is it just an alternative to using an if - else block? what is the exact role of let in this case?
I did read this page, but still a little confused.
if let name = optionalName {
greeting = "Hello, \(name)"
}
This does two things:
it checks if optionalName has a value
if it does, it "unwraps" that value and assigns it to the String called name (which is only available inside of the conditional block).
Note that the type of name is String (not String?).
Without the let (i.e. with just if optionalName), it would still enter the block only if there is a value, but you'd have to manually/explicitly access the String as optionalName!.
// this line declares the variable optionalName which as a String optional which can contain either nil or a string.
//We have it store a string here
var optionalName: String? = "John Appleseed"
//this sets a variable greeting to hello. It is implicity a String. It is not an optional so it can never be nil
var greeting = "Hello!"
//now lets split this into two lines to make it easier. the first just copies optionalName into name. name is now a String optional as well.
let name = optionalName
//now this line checks if name is nil or has a value. if it has a value it executes the if block.
//You can only do this check on optionals. If you try using greeting in an if condition you will get an error
if name{
greeting = "Hello, \(name)"
}
String? is a boxed-type, variable optionalName either contains a String value or nothing(that is nil).
if let name = optionalName is an idiom, it unboxes the value out of optionalName and assign it to name. In the meanwhile, if the name is non-nil, the if branch is executed, otherwise the else branch is executed.