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

时间:2015-01-08 16:58:49

标签: ios swift optional

在我正在制作的节目中,我试图访问网页内容以显示天气。我正在努力克服可选项的概念,我想知道为什么这行代码在“?”时有效。是,但不是没有。

   @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中的一些变量而不是其他变量?

4 个答案:

答案 0 :(得分:2)

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

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.)

答案 1 :(得分:1)

问题在于这一行:

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

...您正在Objective-C / Cocoa中调用一个 failable initializer 的方法。它可以返回nil以指示失败(例如,因为无法使用该编码对数据进行解码)。

因此,在Swift中,如果 no 失败,则此方法返回一个可选的包装字符串(因为只有在没有可选的情况下才能在Swift中使用)。

因此,您必须视为可选项 - 因为可选的包装字符串不是一个字符串 - 它是一个可选项。因此,您打开以访问String。

答案 2 :(得分:0)

来自官方文档

  

返回值

     

通过使用编码将数据中的字节转换为Unicode字符来初始化NSString对象。返回的对象可能与原始接收器不同。如果由于某种原因初始化失败(例如,如果数据不代表编码的有效数据),则返回 nil

使用NSString(data:, encoding:)并不总是返回NSString,它可以返回nil。这就是urlContent的类型为NSString?而不是NSString的原因。因此,您需要在下一行中填写问号。

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

TL; DR:“?”暗示一个变量可以是nil,如果你想访问它,忽略那个nil的可能性,你需要“!”

答案 3 :(得分:0)

您的代码行是&#34;可选链接&#34;的示例。当您尝试访问可能为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

那将编译。为什么?因为插入?会告诉编译器忽略?之后的所有内容lastName nil并将nil返回ucLastName - {{一旦编译器确定uppercaseString

,就永远不会访问属性

在您的情况下,变量lastName == nil是可选的 - 在我的示例中类似于urlContent。您可能没有意识到它是可选的,因为您没有将其声明为一个,但它是,因为它是由函数lastName返回的,它返回一个可选的结果。因此,即使没有意识到它是可选的,编译器也知道它,并通过要求你在代码中插入NSString(data: data, encoding: NSUTF8StringEncoding)值来告诉你。

要求?是好的,因为:

  • 它减少了当您尝试访问?变量的属性或方法时发生的运行时崩溃次数
  • 它需要程序员,要知道你正在处理的值可能是nil。您会注意到如果处理错误,将会发生运行时崩溃。

如果您不需要插入nil,请考虑会发生什么。你的程序会在运行时崩溃,你必须通过在代码中搜索出错的东西来调试它,有时候很少有关于发生了什么的线索。 ?以及随之而来的编译器警告允许您在编译时解决问题,而不是调试运行时崩溃。