Swift字符串与字符串!与字符串?

时间:2016-05-27 22:39:41

标签: swift optional type-safety

我已阅读this个问题以及其他一些问题。但它们与我的问题

有点无关

对于UILabel,如果您未指定?!,则会出现以下错误:

  

@IBOutlet属性具有非可选类型'UILabel'

然后Xcode为您提供 2 选项以便修复它,您可以这样做:

  

修复它添加?形成可选类型UIlabel?
   修复它添加!来形成   隐式解包的可选类型UIlabel?

但是对于字符串,您只需输入string ?!,就不会出现错误为什么会这样?

如果未设置name会怎样?那么我们会nil没有使用?! Swift 来满足'类型安全'吗?

示例:

struct PancakeHouse {
  let name: String // this doesn't have '?' nor '!'
  let photo: UIImage?
  let location: CLLocationCoordinate2D?
  let details: String
}

我主要的疑惑是我们什么时候想使用Optional?

4 个答案:

答案 0 :(得分:8)

文档中涵盖了所有这些:The Swift Programming Language - The Basics

简而言之:

String表示保证存在的String。这个值无法为零,因此直接使用是安全的。

String?代表Optional<String>,可以是nil。您无法直接使用它,必须首先打开它(使用guardif let或强制解包运算符!)以生成String。只要您不强行用!打开它,这也是安全的。

String!也代表Optional<String>,可以是nil。但是,此选项可用于需要非选项的情况,这会导致隐式强制解包。这就像拥有String?并且总是被!隐式强制解包。这些都很危险,因为nil的出现会导致程序崩溃(除非您手动检查nil)。

答案 1 :(得分:6)

对于PancakeHouse结构,name是非可选的。这意味着它的name属性不能为零。编译器将强制执行name初始化PancakeHouse实例时初始化为非零值的要求。它通过要求在为name定义的任何和所有初始化程序中设置PancakeHouse来实现此目的。

对于@IBOutlet属性,这是不可能的。取消归档/加载Interface Builder文件(XIB或Storyboard)时,会设置IB文件中定义的出口,但在其中的对象初始化之后(例如在视图加载期间),总是会出现。因此,在初始化之后但是在设置插座之前必须有一段时间,并且在此期间,插座将是零。 (还有一个问题是出口可能没有在IB文件中设置,并且编译器没有/不能检查它。)这解释了为什么@IBOutlet属性必须是可选的

隐式解包的可选(!)和?的常规可选(@IBOutlet)之间的选择取决于您。参数本质上是使用!允许您将属性视为非可选属性,因此永远不会为零。如果由于某种原因它们是零,那通常被认为是程序员错误(例如插座没有连接,或者你在查看加载完成之前访问它等等),在那些情况下,在开发过程中因崩溃而失败将有助于你抓住这个bug更快。另一方面,将它们声明为常规选项,需要使用任何代码来明确处理由于某种原因可能未设置它们的情况。 Apple默认选择隐式解包,但有些Swift程序员出于自己的原因,使用@IBOutlet属性的常规选项。

答案 2 :(得分:1)

整个&#34;可选&#34;一开始我的事情很糟糕。是什么让它&#34;点击&#34;对我来说,当我不再把它们想象成&#34; String&#34;对象并开始将它们视为泛型。就像&#34; Array&#34;具有&#34; String&#34;的通用标识符;是一个数组,如果它有值,则包含字符串......&#34;字符串?&#34;是一个可选项,如果它有一个值,则是一个字符串。

String - 这总是保证是某种字符串,并且永远不会。声明变量时,必须为其赋值。

的字符串? - 这是一个可选项。它可以是nil,如果它有一个值,它将是一个字符串。要访问可选的值,您必须打开它。

的字符串! - 这是一个可选的,带有语法糖,可以让你直接访问它的值,就像它只是一个字符串一样。它可能是零,但无论出于何种原因,变量周围的背景都向你眨了眨眼,并且说“不要担心,它会有价值。”#34;

答案 3 :(得分:0)

感谢Andrew Madsen的回答和所有其他答案,我自己学到了一点:

struct pairOfOptionalAndNonOptionalAndImplicitUnwrapped{
    var word1 :String?
    var word2 :String
    var word3: String!

    init (a:String, b: String, c: String){
        self.word1 = a // Line A
        self.word2 = b // Line B
        self.word3 = c // Line C
    } //Line BBBB


    func equal() ->Bool{
        return word1 == word2 + word3
    }
}

let wordParts = pairOfOptionalAndNonOptionalAndImplicitUnwrapped (a:"partTwo", b: "part", c:"Two")
wordParts.equal() // Line CCCC
  • 如果我只注释掉A行,我将不会收到错误,因为它是可选的,并且可以将选项设置为nil。
  • 如果我只注释掉B行,我会在BBBB行上遇到编译错误,说:Return from initializer without initializing all stored properties,我知道这是因为我已将属性word2声明为非可选。我告诉编译器我保证让你设置......
  • 如果我只注释掉C行,我不会收到错误,除非我实际在我的对象上运行一个方法。您可以获得的错误是:Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0)当且仅当我运行wordParts.equal()时,因为我告诉我的代码,这是一个可选的含义,它将在其他地方之后设置 / em>实例化/编译。这意味着如果你没有设置lldb可以通过我运行时错误。 (错误将发生在CCCC线上)