类和结构体(Classes and Structures)
最后更新于:2022-04-01 04:55:30
## 类和结构体(Classes and Structures)
### 选择使用谁?(Which one to use?)
请记住,结构体是[值类型](https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_144)。使用结构体并没有一个标识。一个数组包含`[a, b, c]`和另外一个数组同样包含`[a, b, c]`是完全一样的,它们完全可以交换使用。使用第一个还是使用第二个无关紧要,因为它们代表的是同一个东西。这就是为什么数组是结构体。
类是[引用类型](https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_145)。使用类是有一个标识或者有一个特定的生命周期。你需要对一个人类建模为一个类,因为两个不同的人的实例,是两个不同的东西。只是因为两个人有同样的名字和生日,也不能断定这两个人是一样的。但是人的生日是一个结构体,因为日期1950-3-3和另外一个日期1950-3-3是相同的。日期不需要一个标识。
有时,一些事物应该定义为结构体,但是需要兼容AnyObject或者已经在以前的历史版本中定义为类(`NSDate`,`NSSet`)。尽可能的尝试遵守这些规则。
### 定义的案例(Example definition)
以下是一个风格很好的类定义:
~~~
class Circle: Shape {
var x: Int, y: Int
var radius: Double
var diameter: Double {
get {
return radius * 2
}
set {
radius = newValue / 2
}
}
init(x: Int, y: Int, radius: Double) {
self.x = x
self.y = y
self.radius = radius
}
convenience init(x: Int, y: Int, diameter: Double) {
self.init(x: x, y: y, radius: diameter / 2)
}
func describe() -> String {
return "I am a circle at \(centerString()) with an area of \(computeArea())"
}
override func computeArea() -> Double {
return M_PI * radius * radius
}
private func centerString() -> String {
return "(\(x),\(y))"
}
}
~~~
以上例子遵循了以下风格规范:
* 指定属性,变量,常量,参数定义或者其他定义的类型,在冒号后面,紧跟着一个空格,而不是把空格放在冒号前面。比如:`x: Int`和`Circle: Shape`。
* 如果能表示相同的目的和上下文,可以在同一行定义多个变量和结构体。
* 缩进getter,setter的定义和属性观察器的定义。
* 不需要添加`internal`这样的默认的修饰符。同样的,不需要在重写一个方法时添加访问修饰符。
### Self的使用(Use of Self)
为了保持简洁,避免使用 self 关键词,Swift 不需要使用 `self` 来访问对象属性和调用对象方法。
必须使用 `self` 来区分构造器中属性命名和参数命名,还有在闭包表达式中引用属性值(编译器需要区分):
~~~
class BoardLocation {
let row: Int, column: Int
init(row: Int, column: Int) {
self.row = row
self.column = column
let closure = {
println(self.row)
}
}
}
~~~
### 协议遵守(Protocol Conformance)
当我们对一个类添加协议时,推荐使用一个单独的类扩展来实现协议的方法。这可以保持协议相关的方法聚合在一起,同时也可以简单的标识出一个协议对应类中需要实现哪些对应的方法。
同时,别忘了添加// MARK:,注释可以使得代码组织的更好!
推荐做法:
~~~
class MyViewcontroller: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewcontroller: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewcontroller: UIScrollViewDelegate {
// scroll view delegate methods
}
~~~
不推荐做法:
~~~
class MyViewcontroller: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// all methods
}
~~~
### 计算属性(Computed Properties)
为了保持简洁,如果一个计算属性是只读的,请忽略掉get语句。只有在需要定义set语句的时候,才提供get语句。
推荐做法:
~~~
var diameter: Double {
return radius * 2
}
~~~
不推荐做法:
~~~
var diameter: Double {
get {
return radius * 2
}
}
~~~