【问题标题】:Swift trouble with optionals选项的快速问题
【发布时间】:2016-06-02 21:33:10
【问题描述】:

我是一个快速的新手,我在兜圈子试图让可选选项起作用。我已经做了很多谷歌搜索,阅读了 Apple Docs 等,但我在 ViewController 中遇到了这个(简化的)sn-p:

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?)
    }
}

错误是上面标记的行上的Cannot assign value of type 'String?!' to type 'String'。我试过用不同的方式解开它,但就是想不通。

更多代码

发送者是一个自定义的 UIButton 子类,结构如下:

import UIKit

class TestButton: UIButton {
    var urlString: String?
    var busName: String?
}

我已将变量设置为可选,因为我不知道按钮是否具有这些属性。

点击按钮时调用的方法是这样的:

func tapTap(sender: TestButton) {
    print(sender.busName, sender.urlString) // Optional("My Button") Optional("http://www.bbc.co.uk")
    self.performSegueWithIdentifier("segueToWebView", sender: sender)
}

我知道 Swift 选项对于像我这样的新手来说是一个常见的绊脚石,并且有很多关于它们的文档,但我无法弄清楚,所以任何帮助都会很棒。

【问题讨论】:

  • 代码中的第三行 print(sender!.urlString) 不应编译,因为 AnyObject 没有成员 urlString
  • var destUrl:String?替换var destUrl:String并尝试
  • 谢谢大家 - 我现在在火车上,所以会尽快查看您的建议并回复。
  • @NikolaiRuhe:它编译是因为你可以向AnyObject 发送任意(已知)消息,它的行为类似于Objective-C 中的id
  • @MartinR 我刚刚阅读了您的(链接的)帖子——我不知道这一点。感谢您提供翔实的描述!

标签: ios swift


【解决方案1】:

有三个级别的选项:

  • sender: AnyObject? 参数是可选参数。
  • AnyObject 发送任意消息的行为类似于可选 链接并返回一个隐式展开的可选 (比较The strange behaviour of Swift's AnyObject)。
  • var urlString: String? 属性是可选的。

要解决前两个选项,请使用可选绑定/强制转换 具体按钮类:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "segueToWebView") {
        if let button = sender as? TestButton {
           // The type of `button`  is `TestButton`
           // ...
        }
    }
}

现在

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

会编译,但最好用 零合并运算符:

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

请注意,! 运算符不再强制展开!

【讨论】:

  • 感谢您的精彩回答!我意识到“选项中的选项”存在问题,但如果没有您的帮助,我永远找不到解决方案。我将您的第二段代码放在if let 中,它似乎工作正常。非常感谢您的帮助。
【解决方案2】:

你只需要这样做:

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

您的代码中的问题是 destUrl 是一个字符串,但 sender!.urlString 是一个可选的。所以你不能将一个分配给另一个。在分配它之前,您必须解开可选项。要么用 if let 强制打开它(用!)。我建议如果让,但这取决于你。

【讨论】:

    【解决方案3】:

    您正在手动测试 nil 的字符串,但随后您忘记打开它:

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

    (见添加的感叹号。)

    但是像这样解开一个字符串实际上更容易像这样:

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

    ?? 运算符测试 nil,展开或返回右侧,全部在一行中。

    【讨论】:

    • 感谢您提供有关 ?? 的提示运算符 - 将来肯定会派上用场。
    猜你喜欢
    • 2015-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-30
    • 2018-01-31
    • 1970-01-01
    • 2016-11-09
    相关资源
    最近更新 更多