使用 'class' 關(guān)鍵字后跟類名來創(chuàng)建一個(gè)類。在一個(gè)類中乎婿,申明一個(gè)屬性的寫法怪与,同申明一個(gè)常量或變量的寫法是一樣的乖篷。同樣的厅篓,類中的方法(method)同函數(shù)(function)的申明寫法是一樣的秀存。例:
通過在類名后添加括號(hào)來創(chuàng)建一個(gè)類的實(shí)例。使用 ‘點(diǎn)語法’ 來調(diào)用一個(gè)實(shí)例的屬性和方法羽氮。例:
目前這個(gè)版本的 ‘Shape’ 類缺少了一些重要的東西 —— 一個(gè)構(gòu)造器或链,當(dāng)一個(gè)創(chuàng)建一個(gè)實(shí)例的時(shí)候,初始化一個(gè)類档押。使用 ‘init’來創(chuàng)建一個(gè)(構(gòu)造器)
可以看到澳盐,在swift中,init方法不需要調(diào)用父類的init(雖然例子中的類并沒有父類)令宿。這一點(diǎn)和oc中是不同的叼耙。在后面的篇章中,會(huì)對(duì)這一問題有更多的討論粒没。
在這里要留意下筛婉,在構(gòu)造器中‘self’被用來將(NameShape,即本類的)name屬性和 name形參區(qū)分開癞松。當(dāng)你創(chuàng)建一個(gè)類的實(shí)例時(shí)爽撒,構(gòu)造器中的參數(shù)被一一傳遞第就像是一個(gè)函數(shù)調(diào)用。每個(gè)屬性需要分配一個(gè)值 —— 要么是在它(屬性)申明的時(shí)候(像是numberOfSides)要么是在構(gòu)造器中(像是name)响蓉。
使用 ‘deinit’ 創(chuàng)建一個(gè)析構(gòu)器(類似于 dealloc)如果你需要在對(duì)象被釋放前硕勿,做一些清理工作的話。
子類們?cè)谒麄兊念惷蠓慵祝麄兊母割惷Q源武,使用冒號(hào)區(qū)分開。對(duì)類而言想幻,并不需要基于一個(gè)標(biāo)準(zhǔn)的根類(standard root class)粱栖,所以,你可以按需要包含或者是忽略父類脏毯。
子類中的方法查排,如果重寫了父類的實(shí)現(xiàn),那就需要使用 ‘override’ 關(guān)鍵字來標(biāo)示 —— 如果沒有加 ‘override’ 關(guān)鍵字抄沮,而意外的覆蓋了一個(gè)方法跋核,這將會(huì)被編譯器認(rèn)為是一個(gè)錯(cuò)誤。編譯器同樣也會(huì)偵測出那些使用了‘override’關(guān)鍵字——卻實(shí)際上并沒有覆蓋任何父類中的方法——的方法叛买。例:
從圖中的例子中可以看到砂代,在子類的構(gòu)造方法中,首先初始化self的屬性率挣,然后調(diào)用super的構(gòu)造方法刻伊。而且,在調(diào)用super的init 方法前,是不能調(diào)用name屬性的捶箱。原因是name是從父類繼承下來的屬性智什,而在調(diào)用super的init的方法前,self并沒有初始化丁屎,所以也就調(diào)用不到name荠锭。
在oc中,構(gòu)造函數(shù)是首先調(diào)用super的init晨川,這樣先構(gòu)造出self证九,而后可以對(duì)self進(jìn)行進(jìn)一步的初始化操作。swift中共虑,首先將self的私有屬性賦初始值愧怜,而后在構(gòu)造self(通過調(diào)用super的init)。這個(gè)流程和oc是不一樣的妈拌。
實(shí)際上拥坛,熟悉oc的開發(fā)者會(huì)知道,oc中的super實(shí)際上指的是self尘分。也就是說猜惋,在oc中[super init]實(shí)際上使用self調(diào)用super的init方法。這個(gè)過程中音诫,self的所有實(shí)際上都會(huì)被初始化惨奕。而在super的init方法中沒有初始化的屬性(self的私有屬性)就會(huì)有一個(gè)默認(rèn)的值雪位。譬如說竭钝,bool 類型的話就是no,NSArray類型的話就是nil等等雹洗。
swift中香罐,self在調(diào)用super的init方法前必須先將自己的私有屬性全部賦初始值,不然會(huì)報(bào)錯(cuò)
swift中的super.init初始化的僅僅是super中的屬性时肿,和self的私有屬性是沒有關(guān)系的了庇茫。這么做其實(shí)更嚴(yán)謹(jǐn)。
除了簡單的存儲(chǔ)屬性之外螃成,屬性還能有setter和getter方法旦签。例:
oc的類中,每一個(gè)屬性都會(huì)默認(rèn)有一個(gè)setter和getter方法寸宏。而在swift中宁炫,擁有setter/getter方法的是計(jì)算屬性,而用來存儲(chǔ)值(結(jié)果)的存儲(chǔ)屬性氮凝。如例中羔巢,sideLength是存儲(chǔ)屬性,而perimeter是計(jì)算屬性。此二者是不一樣的竿秆。
如果启摄,將例子中的perimeter的set方法改為,perimeter = newValue / 3.0幽钢。那么結(jié)果就會(huì)變成死循環(huán)歉备。因?yàn)榇藭r(shí)perimeter是左值,意味著在set方法中不斷地在調(diào)用set方法搅吁,最終導(dǎo)致死循環(huán)威创。(然而在編譯中是可以通過的)在后面的篇章中會(huì)看到,category中可以添加計(jì)算屬性谎懦,但是不能添加存儲(chǔ)屬性(繼承于NSObject的可以使用runtime肚豺,但實(shí)際上,這樣添加的存儲(chǔ)屬性界拦,也不是真正意義上的屬性)吸申。原因是category是在類的方法列表(method list)中添加方法——擴(kuò)展方法列表。而類的屬性存在于屬性列表(property list)中享甸,所以category是不能添加屬性的截碴。
類實(shí)例管理著屬性列表(的地址),屬性列表中存儲(chǔ)的是類屬性的地址蛉威,category為方法列表添加方法日丹,也就是在方法列表中添加新方法的地址。
在perimeter的setter方法中蚯嫌,新的值有一個(gè)隱式的名稱 —— newValue哲虾。你可以在set之后,添加括號(hào)择示,然后給出一個(gè)顯式的名稱束凑,例如:set(newValue_1)。注意栅盲,EquilateralTriangle類的構(gòu)造器汪诉,有三個(gè)不同的步驟:
1、為子類中申明的屬性(sideLength)賦值
2谈秫、調(diào)用父類的構(gòu)造器
3扒寄、改變?cè)诟割愔卸x的屬性的值。任何額外的初始化步驟拟烫,譬如調(diào)用使用方法该编,getters或者是setters,也能在這個(gè)時(shí)間點(diǎn)中進(jìn)行构灸。
要修改從父類繼承的屬性上渴,或者是調(diào)用方法(類方法除外)岸梨,都要先調(diào)用super的init方法。否則稠氮,self是未初始化的曹阔,會(huì)導(dǎo)致錯(cuò)誤。
如果你不需要對(duì)屬性進(jìn)行計(jì)算隔披,但是你仍然給出一段代碼赃份,希望在屬性將設(shè)置一個(gè)新的值之前,或者已經(jīng)設(shè)置了一個(gè)新的值之后運(yùn)行奢米,那么你可以使用willSet和didSet抓韩。任何時(shí)候(構(gòu)造器之外),只要屬性的值發(fā)生了變化鬓长,你提供的代碼都會(huì)運(yùn)行谒拴。例如,下面的類中涉波,確保類的三角形(屬性)的邊長總是和他的正方形(屬性)的邊長相等英上。例:
當(dāng)遇到可選值的時(shí)候,例如方法啤覆,屬性和下表苍日,你可以在操作符前使用 "?"。如果"?"前的值是nil窗声,那么所有在"?"之后的(代碼相恃,邏輯)都會(huì)被忽略,同時(shí)整個(gè)表達(dá)式是nil的笨觅;否則(即不為nil)拦耐,可選值是被拆包的(unwrapped),并且所有"?"之后的行為都使用拆包后的值屋摇。在兩種情況下整個(gè)表達(dá)式的值是一個(gè)可選值揩魂。例:
所謂可選值幽邓,指的是這個(gè)值可能為空或者不為空炮温,而不是說這個(gè)值的類型是可變的。為空的話牵舵,"?"后面的部分不會(huì)執(zhí)行柒啤。譬如,例中的optionalSquare?.sideLength畸颅。如果担巩,optionalSquare是空的,那么sideLength屬性不會(huì)被調(diào)用没炒,而且作為左值的sideLength也是nil涛癌。