苹果新的编程语言 Swift 语言进阶(八)--属性
属性是特定类、结构或枚举的相关值。属性依据作用域不同分为实例属性与类型属性。还能够依据是否存储分为存储属性和计算属性。
1.1 实例属性
为一个类、结构或枚举定义的属性默认属于实例属性,即该属性属于为该类型创建的不同实例。不同实例具有属性的不同拷贝。
每次当你创建了一个特定类型的新的实例,它总有一组自己的属性。即每一个实例带有自己的一组属性。
实例属性能够是存储属性和计算属性,能够为类和结构的实例定义存储属性和计算属性,而枚举实例仅仅能定义计算属性。
另外全部类型的实例都有一个称为self的隐含的属性。相当于实例本身。
能够在实例方法内使用隐含的self属性来引用当前的实例。
如:
func increment() {
self.count++
// 这里使用self是多余的。count通常引用的就是当前实例的属性,除非//方法increment包括一个与count名字同样的參数。
}
1.2 类型属性
你能为类、结构或枚举类型定义称作类型属性的属性。
类型属性对于那种类型的全部实例,仅有该属性的一份拷贝。
类型属性为特定类型的全部实例定义一个统一的值。比如全部实例都能使用的一个常量属性(与C语言的静态常量类似),或者类型的全部实例都能用的一个存储变量属性(相当于C语言的静态变量)。
对于值类型(结构和枚举类型)。你能为它们定义存储类型属性(能够是变量或者是常量)和计算类型属性,对于类。仅能为它们定义计算类型属性。 计算类型属性总是被声明为变量属性。
与C 和 Objective-C语言不同的是,类型属性是作为类型定义的一部分定义在类型定义的大括号内部。每一个类型属性都属于它所支持的类型。
类型属性的定义语法为:用statickeyword为值类型(结构类型和枚举类型)定义类型属性,使用classkeyword为类定义类型属性。
因为类型本身没有一个初始化方法在初始化期间来为存储类型属性分配值,因此与实例的存储属性不同,你必须为类型的存储属性在定义时就指定一个默认值。
例如以下例所看到的:
struct SomeStructure {
static var storedTypeProperty ="Some value."
static var computedTypeProperty:Int {
// return an Int value here
}
}
class SomeClass {
class var computedTypeProperty:Int {
// return an Int value here
}
}
以上样例为名字为SomeStructure的结构类型定义了一个存储类型属性storedTypeProperty,并指定其默认值为"Some value.”。也定义了一个称为computedTypeProperty的计算属性。
名字为SomeClass的类定义了一个计算属性computedTypeProperty。计算属性必须声明为var类型。
与实例属性一样,类型属性也使用点语法进行查询和设置。比如:
println(SomeClass.computedTypeProperty)
SomeStructure.storedTypeProperty ="Another value.”
1.3、存储属性
一个 存储属性能够是一个常量或一个变量,并作为一个特定类或结构实例的一部分被存储。
一个实例的存储属性的定义语法与通常的常量和变量的定义语法同样,并也支持类型判断,仅仅是存储属性在一个类型内部定义。
你能在存储属性定义时为其提供一个默认值,也可以在初始化期间设置和改动一个存储属性的初始值。
常量属性在初始化设置后不能再被改变。
因为结构是值类型,假设你创建一个结构实例并分配它给一个常量,在该结构实例实例化后。你不能再改动他的属性,即使结构的属性是变量属性。
let rangeOfFourItems =FixedLengthRange(firstValue:0,length:4)
rangeOfFourItems.firstValue =6
// 这将报一个执行时错误
1.4 懒惰存储属性
一个懒惰存储属性是存储属性的特例,一个懒惰存储属性的初始化推迟到须要时进行 。你能在属性声明前加上一个@lazy 来指示该属性是一个懒惰存储属性。
你仅仅能给变量属性声明为懒惰属性。因为常量属性在初始化完毕之前必须包括一个值,因此不能声明一个常量属性作为懒惰属性,。
懒惰属性在某些情况下是实用的,如某个属性的的初始值依赖于某些外部因素。而这些外部因素在实例的初始化完毕之前还不知道。或者属性的初始值须要复杂或者须要耗费大量计算来设置时。
因此在这些情况为了性能考虑须要定义懒惰属性。以便推迟懒惰属性的初始化到须要时进行。
class DataImporter {
var fileName ="data.txt"
}
class DataManager {
@lazy var importer =DataImporter()
var data =String[]()
}
let manager =DataManager()
manager.data +="Some data"
以上样例,因为DataManage实例的importer属性被标记为懒惰属性,因此DataManager实例化时该属性不被创建。仅仅有在使用到该属性时。比如它的fileName被例如以下语句查询时才创建。
println(manager.importer.fileName)
1、5 计算属性
计算属性不实际存储一个值,计算属性通过提供一个getter方法和一个可选的setter方法来间接引出或设置其他属性和值。如:
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)
}
}
}
var square =Rect(origin:Point(x:0.0,y:0.0),
size:Size(width:10.0,height:10.0))
let initialSquareCenter =square.center
square.center =Point(x:15.0,y:15.0)
以上样例为类Rect定义了一个计算属性center,center的属性值由另外的属性origin和size计算确定,该例为center属性定义了两个定制的getter和setter方法。以便可以採用与存储属性同样的方法(点语法)来获取和设置计算属性的值。
假设计算属性的setter方法没有为新设置的值定义名字,默认採用newValue名字,例如以下例所看到的:
struct AlternativeRect {
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 {
origin.x =newValue.x - (size.width / 2)
origin.y =newValue.y - (size.height / 2)
}
}
}
假设仅仅为一个计算属性提供一个getter方法,而没有为其提供setter方法,则该计算属性称为仅仅读的计算属性。仅仅读的计算属性仅仅返回值,但不能为其设置值,假设使用点语法为其设置值,则报一个执行时错误。
- structCuboid {
- varwidth = 0.0,height = 0.0,depth = 0.0
- varvolume:Double {
- returnwidth * height * depth
- }
- }
-
以上为结构Cuboid定义了一个仅仅读的计算属性。getter方法的getkeyword也省略了。
因为计算属性的值是可变的,因此你必须声明计算属性(包含仅仅读的计算属性)作为变量属性(var)。
1.6 属性观察者
属性观察者用来监视属性值的改变。并以特定的动作作为应答。
在每次属性的值被设置,即使新设置的值与属性的当前值同样,为属性定义的属性观察者也被调用。
你能在除了懒惰存储属性外的随意存储属性上添加属性观察者,也能通过类继承并重写继承的超类的属性在一个继承属性(不管存储属性或者是计算属性)上加入属性观察者。
须要注意你不须要为非继承的计算属性定义属性观察者,原因是它们可以直接在计算属性的设置方法中观察和应答属性值的变化。
你能在一个属性上选择定义例如以下两个观察者之中的一个或所有。
willSet观察者在属性值被存储之前被调用,didSet观察者在新的属性值被存储后被马上调用。
假设你实现一个willSet观察者,新的属性值作为一个常量參数传递。你能作为willSet实现的一部分为该參数规定一个名字。
假设你在实现中选择不写參数名字和括号。则使用默认的參数名字newValue。
相似地。实现一个didSet观察者,给它传送一个包括旧的属性值的常量參数。你也能为其命名你希望的參数名字。或者使用默认的參数名字oldValue。
willSet和didSet观察者在属性的首次初始化时不被调用。它们仅在属性的值在初始化完毕后再被改变时才调用。
class StepCounter {
var totalSteps:Int =0 {
willSet(newTotalSteps) {
println("About to set totalSteps to\(newTotalSteps)")
}
didSet {
if totalSteps >oldValue {
println("Added\(totalSteps -oldValue) steps")
}
}
}
}
let stepCounter =StepCounter()
stepCounter.totalSteps =200
// About to set totalSteps to 200
// Added 200 steps
以上类StepCounter为totalSteps属性定义了两个观察者willSet和didSet,willSet观察者为參数定义了一个新的參数名字newTotalSteps。didSet观察者使用默认參数名字。
如样例打印所看到的在属性totalSteps改变前后,两个观察者先后被调用。
1.7 全局和本地变量
全局变量是在随意函数、方法、闭包或类型的上下文外面定义的变量。本地变量是在一个函数、方法、闭包上下文内部定义的变量。
全局和本地变量是一个存储变量,用来存储一个可以设置或读取的特定类型的值。
你可以在全局和本地变量上定义计算变量和定义观察者。
为了性能上的优化考虑,全局变量和全局常量具有计算懒惰特性,与懒惰属性一样,其初始化推迟到须要时进行。
版权全部,转载时请清楚注明链接和出处,谢谢。