为类、结构体以及枚举添加属性
- 在其最简单的形式下,存储属性是一个座位特定类和结构体实例一部分的常量和变量,存储属性要么是变量存储属性(由 var 关键字引入),要么是常量存储属性(由 let 关键字引入)
- 常量结构体实例的存储属性:如果你创建了一个结构体的实例并且把这个实例赋给常量,你不能修改这个实例的属性,即使是声明为变量的属性。
- 延迟存储属性
1 延迟存储属性的初始值在其第一次使用时才进行计算。你可以通过在其声明前标注lazy修饰语来表示一个延迟存储属性。
- 如果被标记为 lazy 修饰符的属性同时被多个线程访问并且属性还没有被初始化,则无法保证属性只初始化一次。
class DataImporter {
var fileName = "data.text"
init() {
print("DataImporter inits")
}
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
}
let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
print(manager.importer.fileName)
- 除了存储属性,类、结构体和枚举也能够定义计算属性,而它实际并不存储值。相反,它提供一个读取器和一个可选的设置器来简介得到和设置其他的属性和值。
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width/2)
let centerY = origin.y + (size.height/2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width/2)
origin.y = newCenter.y - (size.height/2)
}
}
}
- 如果一个计算属性的设置器没有为将要被设置的值定义一个名词,那么它将被默认命名为 newValue
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
return Point(x: origin.x + (size.width/2), y: origin.y + (size.height/2))
}
set {
origin.x = newValue.x - (size.width/2)
origin.y = newValue.y - (size.height/2)
}
}
}
- 如果整个getter 的函数体是一个单一的表达式,那么 getter 隐式返回这个表达式
struct Rect {
var origin: Point
var size = Size()
var center: Point {
get {
Point(x: origin.x + (size.width/2), y: origin.y + (size.height/2))
}
set {
origin.x = newValue.x - (size.width/2)
origin.y = newValue.y - (size.height/2)
}
}
}
- 一个有读取器但是没有设置器的计算属性就是所谓的只读计算属性。只读计算属性返回一个值,也可以通过点语法访问,但是不能被修改为另一个值。
- 你必须用 var 关键字定义计算属性 (包括只读计算属性)为变量属性,因为他们的值不是固定的。let 关键字只用于常量属性,用于明确那些值一旦作为实例初始化就不能更改
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
return Point(x: origin.x + (size.width/2), y: origin.y + (size.height/2))
}
}
- willSet 会在该值被存储之前被调用
- didSet 会在一个新值被存储后背调用
- 如果你实现了一个 willSet 观察者,新的属性值会以常量形式参数传递。你可以再你的 willSet 实现中为这个参数定义名字。如果你没有为它命名,那么它会使用默认的名字 newValue
- 如果你实现了一个 didSet 观察者,一个包含旧属性值的常量形式参数将会被传递。你可以为它命名,也可以使用默认的形式参数名 oldValue。如果你在属性自己的 didSet 观察者里给自己赋值,你赋值的新值就会取代刚刚设置的值
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
stepCounter.totalSteps = 360
stepCounter.totalSteps = 896
- 观察属性的能力同样对全局变量和局部变量有效。全局变量时定义在任何函数、方法、闭包或者类型环境之外的变量。局部变量时定义在函数、方法或者闭包环境之中的变量。
var count: Int = 0 {
willSet(newCount) {
print("About to set totalSteps to \(newCount)")
}
didSet {
if count > oldValue {
print("Added \(count - oldValue) steps")
}
}
}
count = 10
if count == 10 {
print("ten")
}
- 使用 static 关键字来定义类型属性。对于类类型的计算类型属性,你可以使用 class 关键字来允许重写父类的实现。
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty : Int {
return 107
}
}
为类、结构体以及枚举添加方法
- 实例方法是属于特定实例、结构体实例或者枚举实例的函数。他们为这些实例提供功能性,要么通过提供访问和修改实例属性的方法,要么通过提供与实例目的相关的功能。
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
- 每一个类的实例都隐含一个叫做 self 的属性,它完完全全与实例本身相等。你可以使用 self 属性来在当前实例当中调用它自身的方法
- 实际上,你不需要经常在代码中写 self。如果你没有显示地写出 self, Swift 会在你与方法中使用已知属性或者方法的时候,假定你调用了当前实例的属性或者方法。
- 例外就是当一个实例方法的形式参数名与实例中某个属性拥有相同的名字的时候。在这种情况下,形式参数名具有优先权,并且调用属性的时候使用更加严谨的方式就很有必要了。你可以使用 self 属性来区分形式参数名和属性名。
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")
}
- 结构体和枚举是值类型。默认情况下,值类型属性不能被自身的实例方法修改。
- 你可以选择在 func 关键字前放一个 mutating 关键字来指定方可以修改属性
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("This point is now at (\(somePoint.x), \(somePoint.y))")
- Mutating 方法可以指定整个实例给隐含的 self 属性
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("This point is now at (\(somePoint.x), \(somePoint.y))")
- 枚举的异变方法可以设置隐含的 self 属性为相同枚举里的不同成员
enum TriStateSwitch {
case off, low, high
mutating func next() {
switch self {
case .off:
self = .low
case .low:
self = .high
case .high:
self = .off
}
}
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
ovenLight.next()
- 通过在 func 关键字之前使用 static 关键字来明确一个类型方法。类同样可以使用 class 关键字来允许子类重写父类对类型方法的实现。
class SomeClass {
class func someTypeMethod() {
}
}
SomeClass.someTypeMethod()
网友评论