Reputation: 807
I'm new to swift and I don't really understand how to use optional value correctly.
The situation is: Firstly, I have a model class to store some values of its properties and send the request to server to get values. code:
import Foundation
class User: NSObject {
var name: String?
func getInfo(updateUI: () -> ()) {
let manager = AFHTTPSessionManager()
manager.POST(URLString, parameters: nil, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) in
let dic = responseObject as? NSDictionary
self.name = dic?.objectForKey("name")
updateUI()
}, failure: { (task: NSURLSessionDataTask?, error: NSError) in
log.obj(error)
})
}
Secondly, I want to use this model in a ViewController to get values from server and update UI. code:
class UserViewController: UIViewController {
@IBOutlet var nameLabel: UILabel!
var user = User()
override func viewDidLoad() {
super.viewDidLoad()
user.getInfo({
nameLabel.text = user.name!
})
}
}
I think it's a dangerous way to handle this work because there is nothing can ensure that I have a certain name when I want to put it on the label. It works pretty well in most cases but it can crash when fail to get a right value from server(for example, there is no value for key "name").
I have two ideas about questions above:
var name = ""
Test the value before unwarp it like:
if let foo = user.name {
nameLabel.text = foo
}
I want to choose the first way because:
Did I choose a right one? Or both of them didn't understand the usage of optional value and there is a better way? Someone can help me?
Upvotes: 2
Views: 183
Reputation: 51
Your instincts are correct that force unwrapping optional is ill-advised. You are also correct that providing a non-nil default value defeats the purpose of an optional.
if let foo = user.name
binding is a sound way of doing this, but if all you're doing is assigning a value, you can spare yourself the curly braces by using the nil coalescing operator, as pbush25 states:
nameLabel.text = user.name ?? "Default Label Text"
This means "unwrap user.name and if its value is not nil, use it. Otherwise, use the following value:" You can even chain them together if, for example, you wanted to use user's ID as the fallback label text, but the ID might also not exist:
nameLabel.text = user.name ?? user.id ?? "No name or ID"
.
Even if you want to crash in the case that the optional value is nil, it would be better to assert
or use a preconditionFailure()
than to simply force unwrap the optional so that you can at least provide an error message.
Upvotes: 3
Reputation: 5258
You can safely unwrap an optional or give it a default value without declaring a new variable like so:
nameLabel.text = user.name ?? ""
This is called the nil coalescing operator and will try to unwrap an optional, and if the unwrap is unsuccessful will give it the default value that you have placed on the rhs of the operator.
Upvotes: 3