为什么添加可选时此代码有效?

Why does this code work when an optional is added?

在我制作的程序中,我正在尝试访问网络内容以显示天气。我正在为可选的概念而苦苦挣扎,我想知道为什么这行代码在“?”时起作用。有加,但也有。

   @IBAction func pressedSearch(sender: AnyObject) {

        var urlString = "http://www.weather-forecast.com/locations/" + cityField.text.stringByReplacingOccurrencesOfString(" ", withString: "") + "/forecasts/latest"

        var url = NSURL(string: urlString)

        println(urlString)

        let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) in

            var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding)

            var contentArray = urlContent?.componentsSeparatedByString("<span class=\"phrase\">") as Array<String>

            println(contentArray[1])

        }
        task.resume()
    }

这是“?”所在的代码行已添加以使代码正常工作:

var contentArray = urlContent?.componentsSeparatedByString("<span class=\"phrase\">") as Array<String>

“?”是什么意思?做修复错误,为什么我们必须添加“?”和 ”!”在整个 swift 中对某些变量而不是其他变量?

来自官方文档

Return Value

An NSString object initialized by converting the bytes in data into Unicode characters using encoding. The returned object may be different from the original receiver. Returns nil if the initialization fails for some reason (for example if data does not represent valid data for encoding).

使用 NSString(data:, encoding:) 并不总是 return NSString,它可以 return nil。这就是为什么 urlContent 的类型是 NSString? 而不是 NSString 的原因。因此,下一行需要那个问号。

有关的更多信息?和!,请看这里:What is an optional value in Swift?

长话短说:“?”意味着一个变量可以是 nil,如果你想访问它,忽略 nil 的可能性,你需要 "!"

这里有一些代码可以帮助您更好地理解 ?!(包括您告诉机器的内容):

var foo = resultOfAFunctionThatReturnsAQuestionMarkValue()
foo.accessFunction() // "<silence>..."
                     // this could break if foo is nil

var bar = resultOfAFunctionThatReturnsAQuestionMarkValue()
bar?.accessFunction() // "Hey, bro. This might be nil.
                      //       If it is, just ignore the line."
                      // accessFunction() might not be called,
                      // but it won't explode.

var asdf = resultOfAFunctionThatReturnsAQuestionMarkValue()
asdf!.accessFunction() // "Yo, dude. I know for sure this is not nil.
                       //      Don't bother checking first. It's cool."
                       // this could break if asdf if nil
                       // You just lied to the computer.
                       //            (They will remember.)

您的代码行是 "optional chaining" 的示例。当您尝试访问可能是 nil 的方法或变量的 属性 时,会使用它。以此为例:

class Person {
    let firstName = "John"
    var lastName: String? = nil
}

let person = Person()

现在假设您尝试对 person 的姓氏执行操作...您想要它的大写版本,或其他。您的代码可能如下所示:

let ucLastName = person.lastName.uppercaseString

但是 lastNamenil。你不能用它做任何事情,因为它不存在。如果上面的代码能够编译,当你 运行 它会导致程序崩溃。

为防止崩溃,编译器要求您在 lastName 之后插入一个 ?,如下所示:

let ucLastName = person.lastName?.uppercaseString

那将编译。为什么?因为插入 ? 告诉编译器忽略 ? 之后的所有内容 if lastName is nil and return nil to ucLastName - 一旦编译器确定 lastName == nil.

甚至永远不会访问 uppercaseString 属性

在您的例子中,变量 urlContent 是可选的 - 它类似于我示例中的 lastName。你可能没有意识到它是一个可选的,因为你没有将它声明为一个,但它是,因为它是 return 由一个函数编辑的,NSString(data: data, encoding: NSUTF8StringEncoding) return 是一个可选的因此。所以即使 没有意识到它是可选的,编译器知道它,并通过要求你在代码中插入 ? 值来告诉你。

要求 ? 很好,因为:

  • 它减少了当您尝试访问 nil 个变量的属性或方法时发生的运行时崩溃的次数
  • 它需要 程序员意识到你正在处理一个可能是 nil 的值这一事实。您注意到如果处理不当,运行时会崩溃。

考虑一下如果您不需要插入 ? 会发生什么。您的程序会在运行时崩溃,您将不得不通过搜索代码来查找出错的地方来调试它,有时关于发生的事情的线索很少。 ? 以及随之而来的编译器警告,允许您在编译时解决问题,而不是调试运行时崩溃。

问题在于这一行:

var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding)

...您正在调用 Objective-C/Cocoa 中的 可失败初始化程序 的方法。它可以 return nil 表示失败(例如,因为无法使用该编码解码该数据)。

因此,在Swift中,如果没有失败,这个方法returns 一个Optional wrapping a string(因为只有当有一个可选的可以在 Swift).

中使用 nil

因此,您此后必须它视为可选的 - 因为包装字符串的可选 不是 字符串 - 它是可选的.因此,您解包以访问字符串。