I'm a swift newbie and going round in circles trying to get optionals to work. I've done a lot of Googling, read the Apple Docs etc but I'm struggling with this (simplified) snippet from my ViewController:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "segueToWebView") {
// check what we're passing around
print(sender!.urlString) // Optional("http://www.bbc.co.uk")
// do some url validation etc
var destUrl:String
if sender!.urlString == nil{
destUrl = "http://www.google.com"
} else {
destUrl = sender!.urlString // *** Error here ***
}
let targetWebViewController:GDWebViewController = segue.destinationViewController as! GDWebViewController
targetWebViewController.loadURLWithString(destUrl)
targetWebViewController.showsToolbar = true
targetWebViewController.title = sender!.busName // this works correctly too (so isn't that a String?)
}
}
The error is Cannot assign value of type 'String?!' to type 'String'
on the line marked above. I have tried unwrapping it differently but just cant figure it out.
More code
The sender is a custom UIButton subclass with the following structure:
import UIKit
class TestButton: UIButton {
var urlString: String?
var busName: String?
}
I have set the variables to be optional as I don't know whether the button will/won't have those properties.
The method that is called when the button is tapped is this:
func tapTap(sender: TestButton) {
print(sender.busName, sender.urlString) // Optional("My Button") Optional("http://www.bbc.co.uk")
self.performSegueWithIdentifier("segueToWebView", sender: sender)
}
I know Swift optionals is a common stumbling block for newbies like me and there's plenty of docs about them but I can't figure it out so any help would be great.
There are optionals on three levels:
sender: AnyObject?
parameter is an optional.AnyObject
behaves similar to optional
chaining and returns an implicitly unwrapped optional
(compare The strange behaviour of Swift's AnyObject).var urlString: String?
property is an optional.To resolve the first two optionals, use optional binding/casting to the concrete button class:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "segueToWebView") {
if let button = sender as? TestButton {
// The type of `button` is `TestButton`
// ...
}
}
}
Now
var destUrl: String
if button.urlString == nil {
destUrl = "http://www.google.com"
} else {
destUrl = button.urlString!
}
would compile, but that is better handled with the nil-coalescing operator:
let destUrl = button.urlString ?? "http://www.google.com"
Note that there is no forced unwrapping !
operator anymore!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With