一、引言
屬性將值與類,結構體,枚舉進行關聯。 Swift中的屬性分為儲存屬性和計算屬性兩種,儲存屬性用於儲存一個值,其只能用於類與結構體,計算屬性用於計算一個值,其可以用於類,結構體和枚舉。
二、儲存屬性
儲存屬性使用變數或常數來儲存一個值,在宣告儲存屬性時,可以為其設定一個預設值,也可以在建構範例是進行值的設置,屬性可以透過點語法來訪問,結構體的儲存屬性範例程式碼如下:
#struct MyStruct { var property1 = 1 var property2:Int } var obj = MyStruct(property1: 1, property2: 2) //通过点语法进行属性的访问 print(obj.property1,obj.property2)##如上結構體,如果有屬性被宣告成let常數,則此屬性不能夠被修改。還有一點要注意,如果在創建結構體的實例時,使用的是let進行創建,則即便結構體中的屬性是變數也不可進行修改。這和類別有很大差別。 還有一類儲存屬性叫做延時儲存屬性,可以設想一下這樣的情形,類別的某些屬性可能並不是每次類別實例後都會用到,並且有些屬性的建構可能會消耗大量的時間,這時一個比較聰明的設計便是在類別進行實例化時,這類屬性並不被構造,當次類的實例使用到這個屬性時,這個屬性才被構造出來,這樣的屬性被稱為延時儲存屬性,使用lazy關鍵字來聲明,範例如下:
//第一个类 class MyClass1 { init(){ print("MyClass1类被构造") } } class MyClass2 { //声明为延时存储属性 lazy var body = MyClass1() } //在构造MyClass2时 并不会进行body属性的构造 不会有打印信息 var obj2 = MyClass2() //执行下面代码后 会有打印信息 使用body属性使得body被构造 obj2.body注意,如果在多個執行緒中對延時建構屬性進行使用,不能保證其只被構造一次。
三、計算屬性
簡單的理解,計算屬性並不是獨立的用於儲存值的屬性,開發者甚至可以將其理解為一個計算方法,其主要用於透過計算來取得或設定其他儲存屬性的值。範例如下:struct Circle { //圆心 var center:(Double,Double) //半径 var r:Double //周长 将其作为计算属性 var l:Double{ get{ //计算圆的周长 return 2.0*r*M_PI } set{ //通过周长重新计算半径 默认传入的参数名为newValue r = newValue/(M_PI*2) } } } var circle = Circle(center: (0,0), r: 2) print(circle.l) circle.l=24 print(circle.r)透過上面的示範程式碼可以了解,l屬性並非是一個新的屬性,只是透過r屬性來計算出l,或透過l來反推出r,其中有一點要注意,計算屬性中可以創建兩個代碼塊set和get,set代碼塊是可選的,其中會默認生成一個newValue參數來傳遞外界傳進來的數據,get代碼區塊是必須要實現的,當然也可以只實作get程式碼區塊,這時這個屬性將是唯讀的計算屬性,只可以獲取,不能夠設定。還有一點要注意,開發者也可以在set程式碼區塊後面自訂一個參數名稱來接收外界傳入的參數,範例如下:
struct Circle { //圆心 var center:(Double,Double) //半径 var r:Double //周长 将其作为计算属性 var l:Double{ get{ //计算圆的周长 return 2.0*r*M_PI } set(newL){ //通过周长重新计算半径 默认传入的参数名为newValue r = newL/(M_PI*2) } } }#只讀的計算屬性可以進一步的簡寫,因為沒有了set程式碼區塊,所以關鍵字get和括號也可以給省略掉,不會產生歧義,範例如下:##
struct Point { var x:Double var y:Double var center:(Double,Double){ return (x/2,y/2) } }四、屬性監聽器
Swift中的運算屬性中的get和set方法和Objective-C中的get和set方法其實不是一回事,Objective-C提供set和get方法可以讓開發者在屬性將要取得或設定的時候來進行一些自訂的操作,這部分的開發需求在Swift中透過屬性監聽器來實現。
屬性監聽器有willSet和didSet兩種,willSet在屬性值會變更時執行,didSet在屬性值已經變更時執行,並且其中會傳入變更前後的值。範例如下:
struct Point { var x:Double var y:Double{ willSet{ print("将要进行值的更新设置,新的值是:",newValue) } didSet{ print("已经进行值得更新设置,旧的值是:",oldValue) } } var center:(Double,Double){ return (x/2,y/2) } } var point = Point(x: 3, y: 3) //将打印 /* 将要进行值的更新设置,新的值是: 4.0 已经进行值得更新设置,旧的值是: 3.0 */ point.y=4
willSet中預設會產生一個命名為newValue的參數,didSet中會預設產生一個命名為oldValue的參數,也可以自訂這些參數的命名,範例如下:
struct Point { var x:Double var y:Double{ willSet(new){ print("将要进行值的更新设置,新的值是:",new) } didSet(old){ print("已经进行值得更新设置,旧的值是:",old) } } var center:(Double,Double){ return (x/2,y/2) } }#五、實例屬性與型別屬性
##實例屬性是針對與一個類型的實例,類型屬性則是直接針對與類型。每對類型進行一次實例化,其實例都有一套獨立的實例屬性,而類型屬性則是類別的所有實例所共用的,在Objective-C中,通常使用全域的屬性來實現這樣的效果,在Swift中,使用static關鍵字來聲明類型屬性,範例如下:
struct Point { //类型存储属性 static var name:String = "Point" //类型计算属性 static var subName:String{ return "sub"+name } var x:Double var y:Double{ willSet(new){ print("将要进行值的更新设置,新的值是:",new) } didSet(old){ print("已经进行值得更新设置,旧的值是:",old) } } var center:(Double,Double){ return (x/2,y/2) } } //类型属性 通过类型点语法来获取 print(Point.name,Point.subName)注意,有一個特殊的情況是針對於類別的類型計算屬性,如果其需要子類別進行繼承重寫,需要將static關鍵字,換成class關鍵字,範例如下:
class SomeClass { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { return 27 } //支持子类进行重写的计算属性 class var overrideableComputedTypeProperty: Int { return 107 } }