【问题标题】:What is the point of using implicitly unwrapped optional in this example?在这个例子中使用隐式展开的可选有什么意义?
【发布时间】:2016-01-28 16:28:20
【问题描述】:

这是来自文档,Failable Initializers for Classes 部分:

class Product {

     let name: String!
     init?(name: String) {
           self.name = name
           if name.isEmpty { return nil }
     }
}


if let bowTie = Product(name: "") {
   // no need to check if bowTie.name == nil
   print("The product's name is \(bowTie.name)")
}

这是这样描述的:

在上面的例子中,Product 类的 name 属性是 定义为具有隐式展开的可选字符串类型 (细绳!)。因为它是可选类型,这意味着名称 属性在被分配特定之前的默认值为 nil 初始化期间的值。这个 nil 的默认值又意味着 Product 类引入的所有属性都有一个 有效的初始值。因此,Product 的可失败初始化程序 可以在初始化器开始时触发初始化失败 如果它被传递一个空字符串,在分配一个特定的值之前 初始化器中的 name 属性。

看看最后一句话:

因此,Product 的可失败初始化程序 可以在初始化器开始时触发初始化失败 如果它被传递一个空字符串,在分配一个特定的值之前 初始化器中的 name 属性。

这不能从提供的代码中看出。在提供的代码中,可以看到在return nil部分之前已经发生了赋值,并且是String(非可选)或String? (可选)会起作用。

另一件事是,在提供的示例中,如果将其定义为常量,则使用隐式展开的可选项是没有意义的。常量必须在初始化完成之前初始化为默认值。

对此有任何想法,或者是否有人看到不提交雷达的理由?也许我错过了什么?我实际上有一个想法,为什么在这里使用隐式展开可选,但这是一个不好的例子。对我来说,这会更有意义:

class Product {

    var name: String! //let is changed to var

    init?(name: String) {

       if name.isEmpty { return nil } //Check here if passed value is non-empty
       self.name = name
    }
}

这样,可以在对name 属性进行任何分配之前触发初始化失败。

【问题讨论】:

  • 请注意,在上一个示例中,Swift 将抱怨(编译时错误)属性 name 在从失败的初始化程序返回 nil 之前尚未初始化。 name 编辑为可变对象之后不再 :)
  • @dfri 你确定吗?名称被声明为 var(并且隐式展开为可选),因此它可以工作。
  • @Whirlwind 请注意我对评论的编辑:在您将 name 从不可变更改为可变之前,它考虑了您的示例。
  • @dfri 是的,是的。我知道 :) 我没有立即注意到编辑。

标签: ios swift initializer failable


【解决方案1】:

您对误导性文档的所有担忧都是正确的。

另外,请注意,在 Swift 2.2 中,即使在初始化所有属性之前,从可失败的初始化程序提前返回确实有效

class Product {
    let name: String
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}

另一个变化是 deinit 在从可失败初始化程序返回 nil 时不再被调用

来自 Xcode 7.3 beta 2 Release Notes

在类中,在初始化所有存储的属性并调用 super.init() 之前,允许退出可失败 (init?()) 或抛出 (init() throws) 的指定初始化程序。支持此行为,使指定初始化程序与便利初始化程序更加一致。在执行 self.init() 委托之前,便利初始化程序也可能失败。

【讨论】:

  • 出于某种原因,对于包含 immutables(奇怪? )。但这在 Swift 2.2 中可以吗? (例如,如果您在课程中有 let foo: String! 属性,请尝试提前返回)
  • 我指的是隐式展开的可选属性的特殊情况(如 OP 所讨论的),例如let name: String!(注意!)。
  • 啊,我们误解了对方,可能是我混淆了我的第一条评论。我使用的是 XCode 7.2 和 Swift 2.1,所以我的问题是 Swift 2.1。
  • 对不起,我错误地编辑了这个,我想编辑我的答案。
  • 在 Swift 2.1 中使用 let 的隐式解包选项不起作用的原因是因为编译器在这种情况下不能暗示 nil 初始化属性(因为 let 只能设置一次)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-01
  • 1970-01-01
  • 2011-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多