简体   繁体   English

快速解决选择问题

[英]Swift trouble with optionals

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: 我已经做了很多谷歌搜索,阅读Apple Docs等,但我正在努力从我的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' 错误是Cannot assign value of type 'String?!' to type 'String' Cannot assign value of type 'String?!' to type 'String' on the line marked above. 在上面标记的行上Cannot assign value of type 'String?!' to type 'String' 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: sender是一个自定义UIButton子类,具有以下结构:

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. 我知道Swift可选项对于像我这样的新手来说是一个常见的绊脚石,并且有很多关于它们的文档,但我无法弄明白所以任何帮助都会很棒。

There are optionals on three levels: 有三个级别的选项:

  • The sender: AnyObject? sender: AnyObject? parameter is an optional. 参数是可选的。
  • Sending arbitrary messages to AnyObject behaves similar to optional chaining and returns an implicitly unwrapped optional (compare The strange behaviour of Swift's AnyObject ). AnyObject发送任意消息的行为类似于可选链接,并返回一个隐式解包的可选项(比较Swift的AnyObject的奇怪行为 )。
  • The var urlString: String? 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: 会编译,但使用nil-coalescing运算符可以更好地处理:

let destUrl = button.urlString ?? "http://www.google.com"

Note that there is no forced unwrapping ! 请注意,没有强制展开! operator anymore! 操作员了!

You just have to do something like this: 你只需要做这样的事情:

var destUrl:String
if let durl = sender!.urlString {
   destUrl = durl
} else {
   destUrl = "http://www.google.com"
}

The problem in your code is that destUrl is a String but sender!.urlString is an optional. 您的代码中的问题是destUrl是一个String但是发件人!.urlString是可选的。 So you can't assign one to the other. 所以你不能将一个分配给另一个。 You have to unwrap the optional before assign it. 在分配之前,您必须打开可选项。 Either force unwrap it (with !) either with if let. 要么强行解开它(带!),如果让它。 I recommend if let but it's up to you. 我建议如果让,但这取决于你。

You are manually testing the string for nil but then you forget to unwrap it: 你是手动测试字符串为nil但是你忘了打开它:

var destUrl:String
if sender!.urlString == nil{
    destUrl = "http://www.google.com"
} else {
    destUrl = sender!.urlString!
}

(See the added exclamation mark.) (请参阅添加的感叹号。)

But unwrapping a string like this is actually more easy like this: 但解开这样的字符串实际上更容易这样:

let destUrl = sender!.urlString ?? "http://www.google.com"

The ?? ?? operator tests for nil, unwraps or returns the right hand side, all in one line. 操作员测试nil,unwraps或返回右侧,全部在一行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM