屬性將值與類,結構體,枚舉進行關聯。Swift中的屬性分爲存儲屬性和計算屬性兩種,存儲屬性用於存儲一個值,其只能用於類與結構體,計算屬性用於計算一個值,其能夠用於類,結構體和枚舉。ide
存儲屬性使用變量或者常量來存儲一個值,在聲明存儲屬性時,能夠爲其設置一個默認值,也能夠在構造示例是進行值的設置,屬性能夠經過點語法來訪問,結構體的存儲屬性示例代碼以下:idea
struct MyStruct { var property1 = 1 var property2:Int } var obj = MyStruct(property1: 1, property2: 2) //經過點語法進行屬性的訪問 print(obj.property1,obj.property2)
如上結構體,若是有屬性被聲明成let常量,則此屬性不可以被修改。還有一點須要注意,若是在建立結構體的實例時,使用的是let進行建立,則即使結構體中的屬性是變量也不可進行修改。這和類有很大區別。spa
還有一類存儲屬性叫作延時存儲屬性,能夠設想一下這樣的情形,類的某些屬性可能並非在每次類實例後都會用到,而且有些屬性的構造可能會消耗大量的時間,這時一個比較聰明的設計即是在類進行實例化時,這類屬性並不被構造,當次類的實例使用到這個屬性時,這個屬性才被構造出來,這樣的屬性被稱爲延時存儲屬性,使用lazy關鍵字來聲明,示例以下:線程
//第一個類 class MyClass1 { init(){ print("MyClass1類被構造") } } class MyClass2 { //聲明爲延時存儲屬性 lazy var body = MyClass1() } //在構造MyClass2時 並不會進行body屬性的構造 不會有打印信息 var obj2 = MyClass2() //執行下面代碼後 會有打印信息 使用body屬性使得body被構造 obj2.body
注意,若是在多個線程中對延時構造屬性進行使用,不能保證其只被構造一次。設計
簡單的理解,計算屬性並非獨立的用於存儲值的屬性,開發者甚至能夠將其理解爲一個計算方法,其主要用於經過計算來獲取或者設置其餘存儲屬性的值。示例以下:code
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和括號也能夠給省略掉,不會產生歧義,示例以下:ci
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在屬性值已經變化時執行,而且其中會傳入變化先後的值。示例以下:get
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 } }
專一技術,熱愛生活,交流技術,也作朋友。
——琿少 QQ羣:203317592