【问题标题】:Create a Setter Only in Swift仅在 Swift 中创建 Setter
【发布时间】:2014-12-02 13:37:39
【问题描述】:

当我创建一个 setter 时,例如:

var masterFrame: CGRect {
    set {
        _imageView.frame = newValue
        _scrollView.frame = newValue
    }
}

这迫使我做一个吸气剂,我不想这样做。

有没有什么方法可以在没有 getter 的情况下在 Swift 中创建 setter?

【问题讨论】:

  • 不——听起来你最好用一种方法。
  • 什么时候使用只写属性?我从来没有机会这样做。
  • 我有一个类,您可以在其中设置它的主框架,但它负责管理会影响自身的事物(从不更改主框架,因为它是复合的)并且用户不应该使用主框架,除非设置它。
  • setMasterFrame(frame : CGRect) 有什么问题?
  • 不是有什么问题,但我更喜欢二传手,但很明显这将是我必须走的路线

标签: ios swift getter getter-setter


【解决方案1】:

您可以将访问修饰符赋予set 以获得属性,并在didSet 上将其分配给_imageView.frame_scrollView.frame

private(set) var masterFrame: CGRect {
    didSet {
        _imageView.frame = masterFrame
        _scrollView.frame = masterFrame
    }
}

【讨论】:

    【解决方案2】:

    改用didSet

    var masterFrame:CGRect {
        didSet {
            _imageView.frame = masterFrame
            _scrollView.frame = masterFrame
        }
    }
    

    【讨论】:

    • 这可行,但在 API 设计方面也可能会造成混淆/错位。它使 masterFrame 公开以供阅读,这似乎不是目标。
    【解决方案3】:

    如果我真的需要,我会用这个。

    Swift 编译器支持 getter 的一些属性,所以你可以使用@available(*, unavailable):

    public subscript(index: Int) -> T {
        @available(*, unavailable)
        get {
            fatalError("You cannot read from this object.")
        }
        set(v) {
        }
    }
    

    这会将您的意图清楚地传达给代码用户。

    【讨论】:

      【解决方案4】:

      我发现了一个例外,我真的很喜欢 setter only 变量,即当我将闭包作为方法中的唯一参数传递时,其唯一目的是保存它以供以后执行。

      我将其实现为如下方法:

      typealias ThemeSetter = () -> ()
      
      class Theme {
      
          fileprivate var themeSetters:[ThemeSetter] = []
      
          class var shared: Theme {
              struct Singleton {
                  static let instance = Theme()
              }
              return Singleton.instance
          }
              ...
      
          func setColor(_ entry:@escaping ThemeSetter) {
              entry()
              themeSetters.append(entry)
          }
      }
      

      然后我可以按如下方式调用该方法:

          Theme.shared.setColor({
              self.navigationBar.barTintColor = Theme.shared.gameBarTint
          })
      

      但我不喜欢右括号后的右括号,因为我可能在闭包中有很多行。

      因此,了解尾随闭包后,我可以将代码更改为如下所示:

          Theme.shared.setColor() {
              self.navigationBar.barTintColor = Theme.shared.gameBarTint
          }
      

      这完全没问题,也是 Apple 为尾随闭包展示的语法。由于只有一个参数并且我是极简主义者,因此我很想使代码更精简并将其简化为:

          Theme.shared.setColor {
              self.navigationBar.barTintColor = Theme.shared.gameBarTint
          }
      

      这又是 Apple 展示尾随闭包的方式;除此之外,这种方式通常用于某种 Predicate,其中闭包用于告诉方法如何进行排序,或者在异步函数调用结束时将闭包用作完成闭包。我想要的是将闭包分配给...某物。

      如果我用变量替换 setColor 的方法,它看起来像这样:

          var setColor:ThemeSetter? {
              didSet {
                  if setColor != nil {
                      setColor?()
                      themeSetters.append(setColor!)
                      setColor = nil
                  }
              }
          }
      

      现在调用看起来像这样:

          Theme.shared.setColor = {
              self.navigationBar.barTintColor = Theme.shared.gameBarTint
          }
      

      等号表示所有的差异。它表明我正在分配一个闭包并且没有运行一些使用该闭包的函数,即使它确实如此。 :')

      最后说明:这实际上与闭包无关,它只是展示了如何创建一个只有 setter 的变量,但它仍然返回 nil。这并不意味着保护类不让用户像真正的 setter 那样访问变量以进行读取。另外,请原谅关于尾随闭包和单例的教程。

      我可能没有获得足够的投票来成为正确答案,但为什么正确答案是“不,你不能!你必须使用方法调用!”。我说,“Ni”,谁需要所有的语法。只需使用一个变量,不要读回它,或者如果你这样做,不要让它返回任何东西。有点像鲁道夫·亚当科维奇的回答,得到了 0 票。

      【讨论】:

        【解决方案5】:

        当然。你可以只返回一个 nil 并将类型设为可选:

        var color: MyColorEnum? {
            get { return nil }
            set {
              switch newValue! {
              case .Blue:
                view.backgroundColor = UIColor.blueColor()
              case .Red:
                view.backgroundColor = UIColor.redColor()
              }
            }
          }
        

        或者,您可以使用didSet 一起避免该问题:

        var color: MyColorEnum! {
          didSet {
            switch color {
              case .Blue:
                view.backgroundColor = UIColor.blueColor()
              case .Red:
                view.backgroundColor = UIColor.redColor()
              }
          }
        }
        

        【讨论】:

        • 这个解决方案的问题是没有什么可以阻止某人设置nil,使你的应用程序崩溃(或强制你为这种情况添加额外的处理)。
        【解决方案6】:

        要拥有“仅限设置器的属性”,您可以只使用一个设置值的简单函数;例如,如果我们有一个名为 value 的私有属性,我们可以有一个名为 configureWithValue(value:String) 的 setter 方法来更新该属性,但不允许外部访问该属性:

        private var value:String
        
        func configureWithValue(value:String) {
          self.value = value
        }
        

        【讨论】:

          【解决方案7】:

          仅设置属性听起来没有多大意义。您可能应该为此使用一种方法。

          或者,只是让编译器满意并添加一个您从不调用的 getter:

          get {
              return _imageView.frame
          }
          

          【讨论】:

          • 这是我目前的解决方案,但我希望我没有:(
          • 您还可以在 imageView 的框架上放置一个 didSet 闭包,以更新滚动视图的框架。或者使用带有约束的 AutoLayout 使它们相等。
          • Setter 用于设置。属性观察者用于在访问属性之前/之后执行任务。你绝对应该使用didSet 来做你想做的事情。
          • “仅设置属性听起来没有多大意义。”示例:在没有反馈硬件的机器人上设置电机的输出。您可以记住最后设定的速度,并希望硬件能够兑现它,但这并不意味着什么
          【解决方案8】:

          来自docs

          getter 用于读取值,setter 用于写入 价值。 setter 子句是可选的,当只有一个 getter 时 需要,您可以省略这两个子句并简单地返回请求的 直接取值,如只读计算属性中所述。 但是 如果你提供了一个 setter 子句,你还必须提供一个 getter 子句。

          【讨论】:

          • 必须有办法解决这个问题。有很多情况我想要没有 getter 的 setter ...
          • @Aggressor 在 Eonil 的回答中,使用@available(*, unavailable)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-26
          • 1970-01-01
          • 2015-08-05
          • 2014-10-29
          • 1970-01-01
          相关资源
          最近更新 更多