【问题标题】:Swift class with no initializers but with property observer没有初始化器但有属性观察器的 Swift 类
【发布时间】:2015-11-06 02:21:02
【问题描述】:

我刚开始学习 swift 并且对类初始化器有疑问。这是我的示例代码:

struct Resolution {
  var width = 0
  var height = 0
}

let someResolution = Resolution()

class TV {
  var res: Resolution! {
    didSet {
      res.width = 1
      res.height = 1
    }
  }
}

var television = TV()
var resolution = Resolution()
television.res = resolution

我正在尝试使用属性观察器。当我隐式解开结构体的属性观察器类型时,一切正常。否则,它会说“类没有初始化程序。我很困惑为什么要隐式解包结构。提前致谢!

【问题讨论】:

    标签: ios swift struct


    【解决方案1】:

    您的问题并不完全清楚,但我假设您在问为什么不能替换它:

    var res: Resolution! {
    

    …用这个:

    var res: Resolution {
    

    您的线索来自完整的编译器错误消息,您可以通过查看编译器日志(或游乐场控制台,如果您在游乐场)来查看:

    error: class 'TV' has no initializers
    class TV {
          ^
    note: stored property 'res' without initial value prevents synthesized initializers
      var res: Resolution {
          ^
    error: 'TV' cannot be constructed because it has no accessible initializers
    var television = TV()
    

    当属性的类型是Resolution! 时,你是在说,“它可以是 nil,但如果有人试图在它为 nil 时读取它,那将是一场可怕的灾难,我的整个应用程序应该崩溃。”因此 Swift 初始化 TV 并将 res 设置为 nil,并希望您立即将其设置为其他值。

    但是,当属性的类型是 Resolution 时,您是在说,“它永远不能为 nil,永远不能,即使没有人在看也不能。”这意味着res 必须TV 被实例化的那一刻起就有一个值。但是这个值应该是多少?没有默认设置。如果类型是Resolution,你有两种选择:

    1. 使用属性初始值设定项将其设置为某个默认值(这看起来就像您正在尝试做的那样):

       class TV {
         var res: Resolution = Resolution(width: 1, height: 1)
       }
      

      …或者使用初始化器,你可以让 Swift 推断类型:

       class TV {
         var res = Resolution(width: 1, height: 1)
       }
      
    2. 请创建TV 的人在实例化类时指定初始值:

      class TV {
        init(res: Resolution) {
          self.res = res
        }
      
        var res: Resolution {
          didSet {
            res.width = 1
            res.height = 1
          }
        }
      }
      
      var resolution = Resolution()
      var television = TV(res: resolution)
      

    除此之外:所有这些都完全没有意义,因为您在设置分辨率后立即将宽度和高度更改为 1(什么?!),但它确实可以编译。

    那么来自编译器的“综合初始化器”消息? Swift 会自动为你的类创建一个空的init(),但如果有任何非可选属性要初始化,则不会。如果有,您必须编写自己的初始化程序。

    (请注意,如果 TV 是一个结构,那么 Swift 为您生成 init(res:)。它适用于结构,但不适用于类。)

    第三种选择是使类型Resolution?

    class TV {
      var res: Resolution? {
        didSet {
          res?.width = 1
          res?.height = 1
        }
      }
    }
    

    这比 Resolution! 更好,后者只是等待发生的崩溃。隐式解包选项应该只是最后的手段,在非常具体、经过仔细考虑的情况下使用。

    【讨论】:

    • 非常感谢!现在我明白了“!”是怎么回事和初始化程序。
    【解决方案2】:

    每个实例变量在初始化结束时都必须有一个值。

    • 如果您不使用 Optional,那么您必须在此处提供一个实际的 Resolution 实例作为 res 的值 — 而您没有这样做。

    • 如果您使用 Optional,编译器会提供 nil 作为值,因此满足对值的需求。

    一种可能性是这样编写你的类:

    类电视{ var res = 分辨率() { 设置{ res.width = 1 res.height = 1 } } }

    现在res 有了一个初始值:即一个实际的Resolution 实例。

    但你所做的是没有错。当您知道在初始化时无法为实例变量提供值但您打算在不久之后提供一个值时,使用 Optional 是很常见的。

    【讨论】:

    猜你喜欢
    • 2020-03-05
    • 2023-04-02
    • 2015-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多