【问题标题】:When should I access properties with self in swift?我什么时候应该在 swift 中使用 self 访问属性?
【发布时间】:2014-06-14 00:47:18
【问题描述】:

在这样一个简单的例子中,我可以省略 self 来引用 backgroundLayer,因为 backgroundColor 设置在哪个 backgroundLayer 上是明确的。

class SpecialView: UIView {
    let backgroundLayer = CAShapeLayer()

    init() {
        backgroundLayer.backgroundColor = UIColor.greenColor().CGColor
    }
}

但是,就像在 Objective-C 中一样,我们可以通过添加类似命名的局部变量(或常量)来混淆事物。现在在非形状图层上设置了背景颜色:

class SpecialView: UIView {
    let backgroundLayer = CAShapeLayer()

    init() {
        var backgroundLayer = CALayer()

        backgroundLayer.backgroundColor = UIColor.greenColor().CGColor
    }
}

(通过 self.backgroundLayer.backgroundColor 解决)

在 Objective-C 中,我总是避免使用 ivars 来获取属性,并且为了清楚起见,属性总是以 self 为前缀。我不必担心 swift 中的 ivars,但是对于何时应该在 swift 中使用 self 是否还有其他注意事项?

【问题讨论】:

  • 考虑接受解决方案。

标签: swift


【解决方案1】:

唯一需要self 的情况是在引用闭包内的属性时,并且正如您所指出的,将其与同名的局部变量区分开来。

但是,就个人而言,我更喜欢总是写“self”,因为:

  1. 这是一个即时且明显的信号,表明该变量是一个属性。这很重要,因为它是一个属性意味着它的状态可以比局部变量更广泛地变化,并且以不同的方式变化。此外,更改属性比更改局部变量具有更大的影响。
  2. 如果您决定引入与属性同名的参数或变量,则无需更新代码
  3. 代码可以轻松复制进出需要 self 的闭包

【讨论】:

  • 是的,是的。有时简洁和清晰是不一致的 - 总是使用self,这样你就不会被罕见的重叠情况所困扰。
  • @NateCook 我实际上向 Apple 提交了一个关于让自我成为必需的错误,如果你同意,我鼓励你也这样做:)
  • 我喜欢 not 使用 self 的原因是,当闭包捕获迫使你使用 self 时,它会脱颖而出(这很好,因为在闭包中引用 self 会保留它,与其他上下文不同,因此您希望它看起来“不同”)
  • 我认为不使用self 可以保持代码简洁明了。当您使用属性编写公式时尤其如此。并且由于 Xcode 7 的语法着色,哪些变量是本地的,哪些是属性非常清楚。
  • 我同意所有观点。在某种程度上,这取决于个人的设计品味,但大多数时候清晰胜于简洁。
【解决方案2】:

大多数时候我们在访问类属性时可以跳过self.

  1. 但是有一次我们必须使用它:当我们尝试在闭包中设置 self.property 时:

    dispatch_async(dispatch_get_main_queue(), {
        // we cannot assign to properties of self
        self.view = nil 
    
        // but can access properties
        someFunc(view)
    })
    
  2. 当我们应该使用它的时候:这样你就不会弄乱带有类属性的局部变量了:

    class MyClass {
        var someVar: String = "class prop"
    
        func setProperty(someVar:String = "method attribute") -> () {
            print(self.someVar) // Output: class property
            print(someVar) // Output: method attribute
        }
    }
    
  3. 我们可以使用self.的其他地方 之前的属性只是为了表达变量/常量来自。

【讨论】:

    【解决方案3】:

    看着Ray Wenderlich's style guide

    自我使用

    为简洁起见,请避免使用 self,因为 Swift 不要求它访问对象的属性或调用其方法。

    只有在编译器需要时才使用 self(在 @escaping 闭包中,或在初始化程序中以消除参数与属性的歧义)。换句话说,如果它编译时没有 self 则省略它。

    Swift documentation 提出了同样的建议。

    自我属性

    类型的每个实例都有一个名为 self 的隐式属性,它与实例本身完全等价。您可以使用 self 属性在其自己的实例方法中引用当前实例。

    上例中的increment() 方法可以这样写:

    func increment() {
        self.count += 1
    }
    

    在实践中,你不需要经常在代码中编写 self。 如果你没有明确地编写 self,Swift 假设你指的是当前的属性或方法每当您在方法中使用已知的属性或方法名称时,实例。这个假设通过在 Counter 的三个实例方法中使用 count(而不是 self.count)来证明。

    当实例方法的参数名称与该实例的属性具有相同名称时,会出现此规则的主要例外情况。 在这种情况下,参数名称优先,并且变得有必要以更合格的方式提及财产。您使用 self 属性来区分参数名称和属性名称。

    这里,self 消除了称为 x 的方法参数和也称为 x 的实例属性之间的歧义:

    struct Point {
        var x = 0.0, y = 0.0
    
        func isToTheRightOf(x: Double) -> Bool {
            return self.x > x
        }
    }
    
    let somePoint = Point(x: 4.0, y: 5.0)
    if somePoint.isToTheRightOf(x: 1.0) {
        print("This point is to the right of the line where x == 1.0")
    }
    
    // Prints "This point is to the right of the line where x == 1.0"
    

    【讨论】:

    • 你能引用苹果文档的相关部分吗?我找不到推荐。
    • @Apfelsaft 我已经更新了我的答案。相关建议位于“自有财产”部分。 Swift 文档指出“在实践中,您不需要经常在代码中编写 self。”
    • 这不是一个建议,它只是一个关于自我参考的解释,并详细说明了一些你必须使用自我的特殊情况。不要将个人解释转化为推荐。我更喜欢仅以一种方式使用它(始终使用 self)并且不会对我的代码产生歧义,但同样:这是我的偏好。
    【解决方案4】:

    除非绝对必要,否则我将逆流而上,不使用self

    使用self的两个主要原因是

    • 在块中捕获self
    • self 设置为委托时

    在这两种情况下,self 将被捕获为 strong 引用。这可能是您想要的,但在许多情况下,您实际上想要使用 weak

    因此,强制开发者使用self作为例外而不是规则将使这个strong捕获更有意识,并让他反思这个决定。

    【讨论】:

      【解决方案5】:

      正如 Apple 文档在 https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html 中所说的那样

      自我属性

      一个类型的每个实例都有一个隐含的属性叫做 self,它 完全等同于实例本身。你用自己 属性在其自己的实例中引用当前实例 方法。

      上面例子中的 increment() 方法可以写成 像这样:

      func increment() {
          self.count += 1
      }
      

      在实践中,您不需要经常在代码中编写 self。如果 你没有明确写自我,Swift 假设你指的是 每当您使用 方法中的已知属性或方法名称。这个假设是 通过在内部使用 count(而不是 self.count)来证明 Counter 的三个实例方法。

      此规则的主要异常发生在 实例方法与该实例的属性具有相同的名称。在 这种情况下,参数名优先,变成 有必要以更合格的方式提及该财产。你用 用于区分参数名称和参数的 self 属性 属性名称。

      在这里,self 消除了名为 x 的方法参数和 an 也称为 x 的实例属性:

      struct Point {
          var x = 0.0, y = 0.0
          func isToTheRightOf(x: Double) -> Bool {
              return self.x > x
          }
      }
      let somePoint = Point(x: 4.0, y: 5.0)
      if somePoint.isToTheRightOf(x: 1.0) {
          print("This point is to the right of the line where x == 1.0")
      }
      // Prints "This point is to the right of the line where x == 1.0"
      

      没有 self 前缀,Swift 会假设 x 的两种用法 指的是名为x的方法参数。

      我宁愿在使用属性时继续使用 self 以消除这些误解。

      【讨论】:

        【解决方案6】:

        正如 Nick 所说,在 Objective-c 中,我们有 ivars + 综合属性,它们给出了 _internal 变量名称来描述事物。例如。

        @IBOutlet (nonatomic,strong) UITableView *myTableView;
        

        导致 _myTableView 被(最好)在内部引用 - 并且 self.myTableView 在类之外被引用。虽然这是非常黑白的,但在以编程方式实例化视图时考虑例外情况,您可以通过删除 self.

        @interface CustomVC:UIViewController
        {
             UITableView *myTableView; 
        }
        

        很快,公共/内部属性明确了这个范围。 如果它是其他类将与自身交互的公共属性。 否则,如果它是内部跳过自我并避免自动重复。 编译器会在需要时捕获您。

        // UIViewcontroller swift header
        public var title: String? // Localized title for use by a parent controller.
        public var navigationItem: UINavigationItem { get } 
        
        /// In your class
        self.title  = "Clarity"
        self.navigationItem.leftBarButtonItem = UIBarButtonItem()
        
        // In superclass  
         @property(nonatomic, copy) NSString *screenName  // use self.screenName in swift subclass
        
        @IBOutlet myTableView:UITableView  // use self
        public var myTableView:UITableView  // use self
        
        internal var myTableView:UITableView // skip self
        var myTableView:UITableView // skip self 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-05-22
          • 1970-01-01
          • 2010-12-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多