我什么时候应该在swift中使用self访问属性?

时间:2014-06-14 00:47:19

标签: swift

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

class SpecialView: UIView {
    let backgroundLayer = CAShapeLayer()

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

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

class SpecialView: UIView {
    let backgroundLayer = CAShapeLayer()

    init() {
        var backgroundLayer = CALayer()

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

(通过使用self.backgroundLayer.backgroundColor解决此问题)

在Objective-C中,我总是避免使用ivars来获取属性和属性,为了清晰起见,它们总是以self为前缀。我不必担心快速的伊娃,但是我应该在什么时候快速使用自我?

6 个答案:

答案 0 :(得分:77)

唯一需要self次是在引用闭包内的属性时,正如您所指出的那样,将它与具有相同名称的局部变量区分开来。

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

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

答案 1 :(得分:18)

大多数情况下,当我们访问类属性时,我们可以跳过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属性混淆局部变量:

    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. 我们 CAN 使用self.的其他地方 在属性之前,只是为了表达变量/常数来自。

答案 2 :(得分:5)

查看Ray Wenderlich's style guide

  

使用自我

     

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

     

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

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"

答案 3 :(得分:1)

正如Apple文档在https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html

中所述
  

自我属性

     

一个类型的每个实例都有一个名为self的隐式属性   完全等同于实例本身。你使用自我   用于引用其自己实例中的当前实例的属性   方法

     

上面例子中的increment()方法可能已经写好了   像这样:

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

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

     

此规则的主异常在参数名称时发生   instance方法与该实例的属性同名。在   在这种情况下,参数名称优先,它变为   必须以更合格的方式提及房产。你用   self属性来区分参数名称和   财产名称。

     

这里,self消除了名为x和a的方法参数之间的歧义   实例属性,也称为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"
     

没有自我前缀,Swift会假设两者都使用x   引用称为x。

的方法参数

每当我使用某个属性来忽略这些误解时,我宁愿继续使用自我。

答案 4 :(得分:0)

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

@IBOutlet (nonatomic,strong) UITableView *myTableView;

导致_myTableView(最好)在内部引用 - 而self.myTableView在类之外引用。虽然这是非常黑白的,但在编程实例化视图时考虑异常,您可以通过删除self来获得清晰度/简单性/减少样板。

@interface CustomVC:UIViewController
{
     UITableView *myTableView; 
}

在swift中,公共/内部财产澄清了这个范围。 如果它是一个公共财产,其他类将与自我交互。 否则,如果它是内部跳过自我并避免自动重复。 编译器会在需要时捕获您。

// 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 

答案 5 :(得分:0)

除非绝对必要,否则我将不使用self

使用self的两个主要原因是

  • 在块中捕获self
  • self设置为代理人

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

因此,强迫开发人员使用self作为例外而不是规则,将使这strong更加自觉,并让他思考这个决定。