詳解Swift中屬性的聲明與作用
一、引言
屬性將值與類,結(jié)構(gòu)體,枚舉進(jìn)行關(guān)聯(lián)。Swift中的屬性分為存儲屬性和計(jì)算屬性兩種,存儲屬性用于存儲一個值,其只能用于類與結(jié)構(gòu)體,計(jì)算屬性用于計(jì)算一個值,其可以用于類,結(jié)構(gòu)體和枚舉。
二、存儲屬性
存儲屬性使用變量或者常量來存儲一個值,在聲明存儲屬性時,可以為其設(shè)置一個默認(rèn)值,也可以在構(gòu)造示例是進(jìn)行值的設(shè)置,屬性可以通過點(diǎn)語法來訪問,結(jié)構(gòu)體的存儲屬性示例代碼如下:
struct MyStruct { var property1 = 1 var property2:Int } var obj = MyStruct(property1: 1, property2: 2) //通過點(diǎn)語法進(jìn)行屬性的訪問 print(obj.property1,obj.property2)
如上結(jié)構(gòu)體,如果有屬性被聲明成let常量,則此屬性不能夠被修改。還有一點(diǎn)需要注意,如果在創(chuàng)建結(jié)構(gòu)體的實(shí)例時,使用的是let進(jìn)行創(chuàng)建,則即便結(jié)構(gòu)體中的屬性是變量也不可進(jìn)行修改。這和類有很大區(qū)別。
還有一類存儲屬性叫做延時存儲屬性,可以設(shè)想一下這樣的情形,類的某些屬性可能并不是在每次類實(shí)例后都會用到,并且有些屬性的構(gòu)造可能會消耗大量的時間,這時一個比較聰明的設(shè)計(jì)便是在類進(jìn)行實(shí)例化時,這類屬性并不被構(gòu)造,當(dāng)次類的實(shí)例使用到這個屬性時,這個屬性才被構(gòu)造出來,這樣的屬性被稱為延時存儲屬性,使用lazy關(guān)鍵字來聲明,示例如下:
//第一個類 class MyClass1 { init(){ print("MyClass1類被構(gòu)造") } } class MyClass2 { //聲明為延時存儲屬性 lazy var body = MyClass1() } //在構(gòu)造MyClass2時 并不會進(jìn)行body屬性的構(gòu)造 不會有打印信息 var obj2 = MyClass2() //執(zhí)行下面代碼后 會有打印信息 使用body屬性使得body被構(gòu)造 obj2.body
注意,如果在多個線程中對延時構(gòu)造屬性進(jìn)行使用,不能保證其只被構(gòu)造一次。
三、計(jì)算屬性
簡單的理解,計(jì)算屬性并不是獨(dú)立的用于存儲值的屬性,開發(fā)者甚至可以將其理解為一個計(jì)算方法,其主要用于通過計(jì)算來獲取或者設(shè)置其他存儲屬性的值。示例如下:
struct Circle { //圓心 var center:(Double,Double) //半徑 var r:Double //周長 將其作為計(jì)算屬性 var l:Double{ get{ //計(jì)算圓的周長 return 2.0*r*M_PI } set{ //通過周長重新計(jì)算半徑 默認(rèn)傳入的參數(shù)名為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屬性來計(jì)算出l,或者通過l來反推出r,其中有一點(diǎn)需要注意,計(jì)算屬性中可以創(chuàng)建兩個代碼塊set和get,set代碼塊是可選的,其中會默認(rèn)生成一個newValue參數(shù)來傳遞外界傳進(jìn)來的數(shù)據(jù),get代碼塊是必須要實(shí)現(xiàn)的,當(dāng)然也可以只實(shí)現(xiàn)get代碼塊,這時這個屬性將是只讀的計(jì)算屬性,只可以獲取,不能夠設(shè)置。還有一點(diǎn)需要注意,開發(fā)者也可以在set代碼塊后面自定義一個參數(shù)名來接收外界傳入的參數(shù),示例如下:
struct Circle { //圓心 var center:(Double,Double) //半徑 var r:Double //周長 將其作為計(jì)算屬性 var l:Double{ get{ //計(jì)算圓的周長 return 2.0*r*M_PI } set(newL){ //通過周長重新計(jì)算半徑 默認(rèn)傳入的參數(shù)名為newValue r = newL/(M_PI*2) } } }
只讀的計(jì)算屬性可以進(jìn)行進(jìn)一步的簡寫,因?yàn)闆]有了set代碼塊,所以關(guān)鍵字get和括號也可以給省略掉,不會產(chǎn)生歧義,示例如下:
struct Point { var x:Double var y:Double var center:(Double,Double){ return (x/2,y/2) } }
四、屬性監(jiān)聽器
Swift中的計(jì)算屬性中的get和set方法和Objective-C中的get和set方法其實(shí)并非是一回事,Objective-C提供set和get方法可以讓開發(fā)者在屬性將要獲取或者設(shè)置的時候來進(jìn)行一些自定義的操作,這部分的開發(fā)需求在Swift中通過屬性監(jiān)聽器來實(shí)現(xiàn)。
屬性監(jiān)聽器有willSet和didSet兩種,willSet在屬性值將要變化時執(zhí)行,didSet在屬性值已經(jīng)變化時執(zhí)行,并且其中會傳入變化前后的值。示例如下:
struct Point { var x:Double var y:Double{ willSet{ print("將要進(jìn)行值的更新設(shè)置,新的值是:",newValue) } didSet{ print("已經(jīng)進(jìn)行值得更新設(shè)置,舊的值是:",oldValue) } } var center:(Double,Double){ return (x/2,y/2) } } var point = Point(x: 3, y: 3) //將打印 /* 將要進(jìn)行值的更新設(shè)置,新的值是: 4.0 已經(jīng)進(jìn)行值得更新設(shè)置,舊的值是: 3.0 */ point.y=4
willSet中默認(rèn)會生成一個命名為newValue的參數(shù),didSet中會默認(rèn)生成一個命名為oldValue的參數(shù),也可以自定義這些參數(shù)的命名,示例如下:
struct Point { var x:Double var y:Double{ willSet(new){ print("將要進(jìn)行值的更新設(shè)置,新的值是:",new) } didSet(old){ print("已經(jīng)進(jìn)行值得更新設(shè)置,舊的值是:",old) } } var center:(Double,Double){ return (x/2,y/2) } }
五、實(shí)例屬性與類型屬性
實(shí)例屬性是針對與一個類型的實(shí)例,類型屬性則是直接針對與類型。 每對類型進(jìn)行一次實(shí)例化,其實(shí)例都有一套獨(dú)立的實(shí)例屬性,而類型屬性則是類的所有實(shí)例所共用的,在Objective-C中,通常使用全局的屬性來實(shí)現(xiàn)這樣的效果,在Swift中,使用static關(guān)鍵字來聲明類型屬性,示例如下:
struct Point { //類型存儲屬性 static var name:String = "Point" //類型計(jì)算屬性 static var subName:String{ return "sub"+name } var x:Double var y:Double{ willSet(new){ print("將要進(jìn)行值的更新設(shè)置,新的值是:",new) } didSet(old){ print("已經(jīng)進(jìn)行值得更新設(shè)置,舊的值是:",old) } } var center:(Double,Double){ return (x/2,y/2) } } //類型屬性 通過類型點(diǎn)語法來獲取 print(Point.name,Point.subName)
注意,有一種特殊的情況是針對于類的類型計(jì)算屬性,如果其需要子類進(jìn)行繼承重寫,需要將static關(guān)鍵字,換成class關(guān)鍵字,示例如下:
class SomeClass { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { return 27 } //支持子類進(jìn)行重寫的計(jì)算屬性 class var overrideableComputedTypeProperty: Int { return 107 } }
相關(guān)文章
Python查詢Mysql時返回字典結(jié)構(gòu)的代碼
MySQLdb默認(rèn)查詢結(jié)果都是返回tuple,輸出時候不是很方便,必須按照0,1這樣讀取,無意中在網(wǎng)上找到簡單的修改方法,就是傳遞一個cursors.DictCursor就行2012-06-06Python實(shí)現(xiàn)雙色球號碼隨機(jī)生成
和體彩大樂透類似,福彩雙色球也是購買次數(shù)最多的彩種之一,相比大樂透,雙色球更容易中小獎。本文將介紹?Python?實(shí)習(xí)雙色球彩票自由的流程,感興趣的可以了解一下2022-05-05如何解決django配置settings時遇到Could not import settings ''conf.loca
這里記錄一下在項(xiàng)目中遇到django配置settings時遇到Could not import settings 'conf.local'的解決方法,有同樣問題的小伙伴們參考下吧2014-11-11Python3.7 版本 lxml 模塊無法導(dǎo)入etree 問題及解決方法
這篇文章主要介紹了Python3.7 版本 lxml 模塊無法導(dǎo)入etree 問題及解決方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01Python實(shí)現(xiàn)的讀寫json文件功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)的讀寫json文件功能,結(jié)合實(shí)例形式分析了Python針對json文件進(jìn)行讀寫的常見操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-06-06