Swift與OC的語(yǔ)法簡(jiǎn)單對(duì)比(常用語(yǔ)法二)

20- 枚舉,枚舉原始值,枚舉相關(guān)值,switch提取枚舉關(guān)聯(lián)值


Swift枚舉:

Swift中的枚舉比OC中的枚舉強(qiáng)大,因?yàn)镾wift中的枚舉是一等類型,

它可以像類和結(jié)構(gòu)體一樣增加屬性和方法

格式:

enum Method{

case枚舉值

}

enumMethod{

case Add

case Sub

case Mul

case Div

可以連在一起寫

caseAdd, Sub, Mul, Div

}

可以使用枚舉類型變量或常量接收枚舉值

varm:Method= .Add

注意:如果變量或常量沒有指定類型,那么前面必須加上該值屬于哪個(gè)枚舉類型

varm1 =Method.Add

利用Switch匹配

注意:如果case中包含了所有的值,可以不寫default.

如果case中沒有包含枚舉中所有的值,必須寫default

switch(Method.Add){

caseMethod.Add:

print("加法")

caseMethod.Sub:

print("減法")

caseMethod.Mul:

print("除法")

caseMethod.Div:

print("乘法")

default:

print("都不是")

}

原始值:

OC中枚舉的本質(zhì)就是整數(shù),所以O(shè)C中的枚舉是有原始值的,默認(rèn)是從0開始

而Swift中的枚舉默認(rèn)是沒有原始值的,但是可以在定義時(shí)告訴系統(tǒng)讓枚舉有原始值

enum Method:枚舉值原始值類型{

case枚舉值

}

enumMethod2:Int{

可以連在一起寫

caseAdd, Sub, Mul, Div

}

和OC中的枚舉一樣,也可以指定原始值,后面的值默認(rèn)+1

enumMethod3:Int{

caseAdd =5, Sub, Mul, Div

}

Swift中的枚舉除了可以指定整形以外還可以指定其它類型,

但是如果指定其它類型,必須給所有枚舉值賦值,因?yàn)椴荒茏詣?dòng)遞增

enumMethod4:Double{

可以連在一起寫

caseAdd =5.0, Sub =6.0, Mul =6.1, Div =8.0

}

rawValue代表將枚舉值轉(zhuǎn)換為原始值,注意老版本中轉(zhuǎn)換為原始值的方法名叫toRaw

Method4.Sub.rawValue

原始值轉(zhuǎn)換為枚舉值

enumMethod5:String{

caseAdd ="add", Sub ="sub", Mul ="mul", Div ="div"

}

通過原始值創(chuàng)建枚舉值

注意:

1.原始值區(qū)分大小寫

2.返回的是一個(gè)可選值,因?yàn)樵贾祵?duì)應(yīng)的枚舉值不一定存在

3.老版本中為fromRaw("add")

letm2 =Method5(rawValue:"add")

print(m2)

funcchooseMethod(op:String)

{

由于返回是可選類型,所以有可能為nil,最好使用可選綁定

ifletopE =Method5(rawValue: op){

switch(opE){

case.Add:

print("加法")

case.Sub:

print("減法")

case.Mul:

print("除法")

case.Div:

print("乘法")

}

}

}

枚舉相關(guān)值:

可以讓枚舉值對(duì)應(yīng)的原始值不是唯一的,而是一個(gè)變量.

每一個(gè)枚舉可以是在某種模式下的一些特定值

enumlineSegmentDescriptor{

caseStartAndEndPattern(start:Double, end:Double)

caseStartAndLengthPattern(start: Double, length:Double)

}

varlsd =lineSegmentDescriptor.StartAndLengthPattern(start:0.0, length:100.0)

lsd=lineSegmentDescriptor.StartAndEndPattern(start:0.0, end:50.0)

利用switch提取枚舉關(guān)聯(lián)值

switchlsd

{

caselet.StartAndEndPattern(s, e):

print("start =\(s) end =\(e)")

case.StartAndLengthPattern(lets,letl):

print("start =\(s) lenght =\(l)")

}



21-結(jié)構(gòu)體,結(jié)構(gòu)體構(gòu)造器,定義成員方法


結(jié)構(gòu)體:

結(jié)構(gòu)體是用于封裝不同或相同類型的數(shù)據(jù)的

Swift中的結(jié)構(gòu)體是一類類型,可以定義屬性和方法(甚至構(gòu)造方法和析構(gòu)方法等)

格式:

struct結(jié)構(gòu)體名稱{

結(jié)構(gòu)體屬性和方法

}

structRect {

varwidth:Double=0.0

varheight:Double=0.0

}

如果結(jié)構(gòu)體的屬性有默認(rèn)值,可以直接使用()構(gòu)造一個(gè)結(jié)構(gòu)體

如果結(jié)構(gòu)體的屬性沒有默認(rèn)值,必須使用逐一構(gòu)造器實(shí)例化結(jié)構(gòu)體

varr =Rect()

print("width =\(r.width) height =\(r.height)")

輸出結(jié)果:width = 0.0 height = 0.0

結(jié)構(gòu)體屬性的訪問使用.語(yǔ)法

varr =Rect()

r.width=100

r.height=99

print("width =\(r.width) height =\(r.height)")

輸出結(jié)果:width = 100.0 height = 99.0

結(jié)構(gòu)體構(gòu)造器

Swift中的結(jié)構(gòu)體和類跟其它面向?qū)ο笳Z(yǔ)言一樣都有構(gòu)造函數(shù),而OC是沒有的

Swift要求實(shí)例化一個(gè)結(jié)構(gòu)體或類的時(shí)候,所有的成員變量都必須有初始值,

構(gòu)造函數(shù)的意義就是用于初始化所有成員變量的,而不是分配內(nèi)存,分配內(nèi)存是系統(tǒng)幫我們做的.

如果結(jié)構(gòu)體中的所有屬性都有默認(rèn)值,可以調(diào)用()構(gòu)造一個(gè)結(jié)構(gòu)體實(shí)例

如果結(jié)構(gòu)體中的屬性沒有默認(rèn)值,可以自定義構(gòu)造器,并在構(gòu)造器中給所有的屬性賦值

其實(shí)結(jié)構(gòu)體有一個(gè)默認(rèn)的逐一構(gòu)造器,用于在初始化時(shí)給所有屬性賦值

structRect2 {

varwidth:Double

varheight:Double=0.0

}

逐一構(gòu)造器

varr1 =Rect2(width:10.0, height:10.0);

錯(cuò)誤寫法,順序必須和結(jié)構(gòu)體中成員的順序一致

var r1 = Rect2(height: 10.0, width: 10.0);

錯(cuò)誤寫法,必須包含所有成員

var r1 = Rect2(height: 10.0);

結(jié)構(gòu)體中定義成員方法

在C和OC中結(jié)構(gòu)體只有屬性,而Swift中結(jié)構(gòu)體中還可以定義方法

structRect {

varwidth:Double

varheight:Double=0.0

給結(jié)構(gòu)體定義一個(gè)方法,該方法屬于該結(jié)構(gòu)體

結(jié)構(gòu)體中的成員方法必須使用某個(gè)實(shí)例調(diào)用

成員方法可以訪問成員屬性

funcgetWidth() ->Double{

returnwidth

}

}

varr =Rect(width:10.0, height:20.0)

結(jié)構(gòu)體中的成員方法是和某個(gè)實(shí)例對(duì)象綁定在一起的,

所以誰(shuí)調(diào)用,方法中訪問的屬性就屬于誰(shuí)

print(r.getWidth())

輸出結(jié)果:10.0

varr1 =Rect(width:30.0, height:20.0)

print(r1.getWidth())

輸出結(jié)果:30.0

結(jié)構(gòu)體是值類型

structRect {

varwidth:Double

varheight:Double=0.0

funcshow() ->Void{

print("width =\(width) height =\(height)")

}

}

varr1 =Rect(width:10.0, height:10.0)

varr2 =r1

r1.show()

r2.show()

r1.width=20.0

結(jié)構(gòu)體是值類型,結(jié)構(gòu)體之間的賦值其實(shí)是將r1中的值完全拷貝一份到r2中,

所以他們是兩個(gè)不同的實(shí)例

r1.show()

r2.show()

輸出結(jié)果:

width = 10.0 height = 10.0

width = 10.0 height = 10.0

width = 20.0 height = 10.0

width = 10.0 height = 10.0



22-類,類的恒等運(yùn)算


類的基本定義

Swift中的結(jié)構(gòu)體和類非常相似,但是又有不同之處

類是具有相同屬性和方法的抽象

格式:

class類名稱{

類的屬性和方法

}

classRect {

varwidth:Double=0.0

varheight:Double=0.0

funcshow() ->Void{

print("width =\(width) height =\(height)")

}

}

類沒有逐一構(gòu)造器

var r1 = Rect(width: 10.0, height: 10.0)

varr1 =Rect()

r1.show()

varr2 =r1

r2.show()

輸出結(jié)果:

width = 0.0 height = 0.0

width = 0.0 height = 0.0

類是引用類型,類之間的賦值其實(shí)是將r2指向了r1的存儲(chǔ)空間

所以他們是兩個(gè)只想同一塊存儲(chǔ)空間,修改其中一個(gè)會(huì)影響到另外一個(gè)

r1.width=99

r1.show()

r2.show()

輸出結(jié)果:

width = 99.0 height = 0.0

width = 99.0 height = 0.0

恒等運(yùn)算符

用于判斷是否是同一個(gè)實(shí)例,也就是是否指向同一塊存儲(chǔ)空間

=== !==

varr3 =Rect()

ifr1===r3

{

print("指向同一塊存儲(chǔ)空間")

}

輸出結(jié)果:

指向不同的存儲(chǔ)空間



23- 屬性,存儲(chǔ)屬性,延遲存儲(chǔ)屬性,計(jì)算屬性,屬性觀察器,類屬性


存儲(chǔ)屬性

Swift中的存儲(chǔ)屬性就是以前學(xué)習(xí)OC中的普通屬性

在結(jié)構(gòu)體或者類中定義的屬性,默認(rèn)就是存儲(chǔ)屬性

structPerson {

varname:String

varage:Int

}

varp:Person=Person(name:"lzh", age:30)

p.name="gxq"

p.age=50

常量存儲(chǔ)屬性

常量存儲(chǔ)屬性只能在定義時(shí)或構(gòu)造時(shí)修改

構(gòu)造好一個(gè)對(duì)象之后不能對(duì)常量存儲(chǔ)屬性進(jìn)行修改

structPerson {

varname:String

varage:Int

letcard:String身份證

}

varp:Person=Person(name:"gaowei", age:30, card:"123456")

p.name="gxq"

p.age=50

構(gòu)造好對(duì)象之后不能修改常量存儲(chǔ)屬性

以下寫法是錯(cuò)誤的

p.card = "56789"

結(jié)構(gòu)體和類常量與存儲(chǔ)屬性的關(guān)系

結(jié)構(gòu)體和枚舉是值類型

類是引用類型

structPerson {

varname:String

varage:Int

}

letp:Person=Person(name:"lzh", age:30)

因?yàn)榻Y(jié)構(gòu)體是值類型,所以不能修改結(jié)構(gòu)體常量中的屬性

不能修改結(jié)構(gòu)體/枚舉常量對(duì)象中的值,因?yàn)樗赶虻膶?duì)象是一個(gè)常量

以下寫法錯(cuò)誤

p.name =“gxq"

不能修改結(jié)構(gòu)體常量對(duì)象的值

以下寫法錯(cuò)誤

p=Person(name:"gxq", age:50)

classPerson {

varname:String="lnj"

varage:Int=30

}

letp:Person=Person()

可以修改類常量中的值,因?yàn)樗赶虻膶?duì)象不是一個(gè)常量

p.name=“l(fā)zh"

不可以修改類常量的指向

以下寫法是錯(cuò)誤的

p = Person4()

延遲存儲(chǔ)屬性

Swift語(yǔ)言中所有的存儲(chǔ)屬性必須有初始值,

也就是當(dāng)構(gòu)造完一個(gè)對(duì)象后,對(duì)象中所有的存儲(chǔ)屬性必須有初始值

但是也有例外

其中延遲存儲(chǔ)屬性可以將屬性的初始化推遲到該屬性第一次被調(diào)用的時(shí)候

懶加載應(yīng)用場(chǎng)景:

1.有可能不會(huì)用到

2.依賴于其它值

classLine {

varstart:Double=0.0

varend:Double=0.0

如果不是lazy屬性,定義的時(shí)候?qū)ο筮€沒有初始化,所以不能訪問self

如果加上lazy,代表使用時(shí)才會(huì)加載,也就是使用到length屬性時(shí)才會(huì)調(diào)用self

而訪問一個(gè)類的屬性必須通過對(duì)象方法

所以訪問時(shí)對(duì)象已經(jīng)初始化完成了,可以使用self

lazyvarlength:Double=self.getLenght()

通過閉包懶加載

lazyvarcontainer:Array = {

print("懶加載")

vararrM = []

returnarrMas[AnyObject]

}()

funcgetLenght() ->Double

{

print("懶加載")

returnend-start

}

}

varline =Line()

line.end=150.0

print("創(chuàng)建對(duì)象完畢")

print(line.length)

vararrM =line.container

arrM.append("1")

arrM.append(5)

print(arrM)

輸出結(jié)果:

創(chuàng)建對(duì)象完畢

懶加載

150.0

懶加載

[1, 5]

計(jì)算屬性

1.Swift中的計(jì)算屬性不直接存儲(chǔ)值

跟存儲(chǔ)屬性不同,沒有任何的"后端存儲(chǔ)與之對(duì)應(yīng)"

2.計(jì)算屬性用于計(jì)算,可以實(shí)現(xiàn)setter和getter這兩種計(jì)算方法

3.枚舉不可以有存儲(chǔ)屬性,但是允許有計(jì)算屬性

setter對(duì)象.屬性=值

getter var value =對(duì)象.屬性

structRect {

varorigion: (x:Double, y:Double) = (0,0)

varsize: (w:Double, h:Double) = (0,0)

由于center的值是通過起點(diǎn)和寬高計(jì)算出來(lái)的,所以沒有必要提供一個(gè)存儲(chǔ)屬性

varcenter: (x:Double, y:Double) {

get{

return(origion.x +size.w/2,origion.y +size.h/2)

}

set{

注意:計(jì)算屬性不具備存儲(chǔ)功能,所以不能給計(jì)算屬性賦值

如果賦值會(huì)發(fā)生運(yùn)行時(shí)錯(cuò)誤

注意: setter可以自己傳遞一個(gè)參數(shù),也可以使用系統(tǒng)默認(rèn)的參數(shù)newValue

如果要使用系統(tǒng)自帶的參數(shù),必須刪除自定義參數(shù)

origion.x = newValue.x -size.w /2

origion.y = newValue.y -size.h /2

}

}

}

varr =Rect()

r.origion= (0,0)

r.size= (100,100)

print("center.x =\(r.center.x) center.y =\(r.center.y)")

輸出結(jié)果:center.x = 50.0 center.y = 50.0

r.center= (100,100)

print("origion.x =\(r.origion.x) origion.y =\(r.origion.y)")

輸出結(jié)果:origion.x = 50.0 origion.y = 50.0

print("center.x =\(r.center.x) center.y =\(r.center.y)")

輸出結(jié)果:center.x = 100.0 center.y = 100.0

只讀計(jì)算屬性

對(duì)應(yīng)OC中的readonly屬性

所謂的只讀屬性就是只提供了getter方法,沒有提供setter方法

classLine {

varstart:Double=0.0

varend:Double=0.0

只讀屬性,只讀屬性必須是變量var,不能是常量let

例如想獲取長(zhǎng)度

只能通過計(jì)算獲得,而不需要外界設(shè)置,可以設(shè)置為只讀計(jì)算屬性

varlength:Double{

只讀屬性的簡(jiǎn)寫,可以省略get{}

returnend-start

}

}

varline =Line()

line.end=100

print(line.length)

輸出結(jié)果:100.0

屬性觀察器

類似OC中的KVO

可以用于監(jiān)聽屬性什么時(shí)候被修改,只有屬性被修改才會(huì)調(diào)用

有兩種屬性觀察器:

1.willSet,在設(shè)置新值之前調(diào)用

2.didSet,在設(shè)置新值之后調(diào)用

可以直接為除計(jì)算屬性和lazy屬性之外的存儲(chǔ)屬性添加屬性觀察器

但是可以在繼承類中為父類的計(jì)算屬性提供屬性觀察器

因?yàn)樵谟?jì)算屬性中也可以監(jiān)聽到屬性的改變

所以給計(jì)算屬性添加屬性觀察器沒有任何意義

classLine {

varstart:Double=0.0{

willSet{

print("willSet newValue =\(newValue)")

}

didSet{

print("didSet oldValue =\(oldValue)")

}

}

varend:Double=0.0

}

varl =Line()

l.start=10.0

輸出結(jié)果:

willSet newValue = 10.0

didSet oldValue = 0.0

類屬性

在結(jié)構(gòu)體和枚舉中用static

在類中使用class,并且類中不允許將存儲(chǔ)屬性設(shè)置為類屬性

structPerson {

普通的屬性是每個(gè)對(duì)象一份

varname:String=“l(fā)zh"

類屬性是素有對(duì)象共用一份

staticvargender:String="man"

staticvarage:Int{

return30

}

funcshow()

{

print("gender =\(Person.gender) name =\(name)")

}

}

varp =Person()

print("gender =\(Person.gender)")

輸出結(jié)果:gender = man

varp1 =Person()

類屬性是所有對(duì)象共用一份

print("gender =\(Person.gender)")

p.show()

輸出結(jié)果:

gender = man

gender = man name = lzh

可以將計(jì)算屬性設(shè)置為類屬性

print("age =\(Person.age)")

輸出結(jié)果:age = 30

classPerson {

普通的屬性是每個(gè)對(duì)象一份

varname:String="lnj"

類中不允許將存儲(chǔ)屬性定義為類屬性

下面為錯(cuò)誤寫法

class var gender:String = "man"

類中只能將計(jì)算屬性定義為類屬性

classvarage:Int{

return30

}

funcshow()

{

print("age =\(Person.age)")

}

}

varp =Person()

print("age =\(Person.age)")

p.show()

輸出結(jié)果:

age = 30

age = 30



24-方法,self關(guān)鍵字,mutating方法,類方法


方法

隸屬于每一個(gè)類或結(jié)構(gòu)體的函數(shù)稱之為方法:

方法分為類方法和實(shí)例方法,對(duì)應(yīng)OC中的+ -方法

實(shí)例方法:實(shí)例方法一定是通過對(duì)象來(lái)調(diào)用的,實(shí)例方法隸屬于某一個(gè)類

classPerson {

var_name:String="lzh"

var_age:Int=30

實(shí)例方法一定是通過對(duì)象來(lái)調(diào)用的,實(shí)例方法隸屬于某一個(gè)類

funcsetName(name:String,age:Int)

如果不希望某個(gè)參數(shù)作為外部參數(shù),可以在參數(shù)前面加上_,忽略外部參數(shù)

funcsetName(name:String,_age:Int)

{

_name= name

_age= age

}

funcshow()

{

print("name =\(_name) age =\(_age)")

}

}

varp =Person()

由于第一個(gè)參數(shù)可以通過方法名稱指定,所以默認(rèn)第一個(gè)參數(shù)不作為外部參數(shù)

p.setName("zs", age: 88)

可以在參數(shù)前面加上_,忽略外部參數(shù)

p.setName("zs",88)

p.show()

輸出結(jié)果:name = zs age = 88

self關(guān)鍵字

Swift中的self和OC中的self基本一樣. self指當(dāng)前對(duì)象

如果self在對(duì)象方法中代表當(dāng)前對(duì)象.但是在類方法中沒有self

classPerson {

varname:String=“l(fā)zh"

varage:Int=30

當(dāng)參數(shù)名稱和屬性名稱一模一樣時(shí),

無(wú)法區(qū)分哪個(gè)是參數(shù)哪個(gè)是屬性

這個(gè)時(shí)候可以通過self明確的來(lái)區(qū)分參數(shù)和屬性

funcsetName(name:String, age:Int)

{

默認(rèn)情況下, _name和_age前面有一個(gè)默認(rèn)的self關(guān)鍵字,

因?yàn)樗凶兞慷夹枰榷x再使用

而setName方法中并沒有定義過_name和_age,

而是在屬性中定義的,所以setName中訪問的其實(shí)是屬性,

編譯器默認(rèn)幫我們?cè)谇懊婕恿艘粋€(gè)self.

_name = name

_age = age

self.name= name

self.age= age

}

funcshow()

{

print("name =\(name) age =\(age)")

}

}

varp =Person()

p.setName("xq", age:20)

p.show()

輸出結(jié)果:name = xq age = 20

mutating方法

值類型(結(jié)構(gòu)體和枚舉)默認(rèn)方法是不可以修改屬性的

如果需要修改屬性

需要在方法前加上mutating關(guān)鍵字,讓該方法變?yōu)橐粋€(gè)改變方法

structPerson {

varname:String="lzh"

varage:Int=30

值類型(結(jié)構(gòu)體和枚舉)默認(rèn)方法是不可以修改屬性的

如果需要修改屬性

需要在方法前加上mutating關(guān)鍵字,讓該方法變?yōu)橐粋€(gè)改變方法

注意:類不需要,因?yàn)轭惖膶?shí)例方法默認(rèn)就可以修改

mutatingfuncsetName(name:String, age:Int)

{

self.name= name

self.age= age

}

funcshow()

{

print("name =\(name) age =\(age)")

}

}

varp =Person()

p.setName("zs", age:99)

p.show()

輸出結(jié)果:name = zs age = 99

enumLightSwitch{

caseOFF, ON

mutatingfuncnext()

{

switchself{

caseOFF:

self=ON

caseON:

self=OFF

}

}

}

varls:LightSwitch=LightSwitch.OFF

ifls==LightSwitch.OFF

{

print("off")

}

ls.next()

ifls==LightSwitch.ON

{

print("on")

}

輸出結(jié)果:

off

on

類方法:

和類屬性一樣通過類名來(lái)調(diào)用

類方法通過static關(guān)鍵字(結(jié)構(gòu)體/枚舉), class(類)

類方法中不存在self

structPerson {

varname:String=“l(fā)zh"

staticvarcard:String="123456"

funcshow()

{

print("name =\(self.name) card =\(Person.card)")

}

staticfuncstaticShow()

{

類方法中沒有self

print("name = \(self.name) card = \(Person.card)")

靜態(tài)方法對(duì)應(yīng)OC中的+號(hào)方法,和OC一樣在類方法中不能訪問非靜態(tài)屬性

print("card =\(Person.card)")

}

}

varp =Person()

p.show()

Person.staticShow()

輸出結(jié)果:

name = lzh card = 123456

card = 123456

classPerson {

varname:String="lzh"

classvarcard:String{

return"123456"

}

funcshow()

{

print("name =\(self.name) card =\(Person.card)")

}

classfuncstaticShow()

{

類方法中沒有self

print("name = \(self.name) card = \(Person.card)")

靜態(tài)方法對(duì)應(yīng)OC中的+號(hào)方法,和OC一樣在類方法中不能訪問非靜態(tài)屬性

print("card =\(Person.card)")

}

}

varp =Person()

p.show()

Person.staticShow()

輸出結(jié)果:

name = lzh card = 123456

card = 123456



25- 下標(biāo)subscripts


subscripts(下標(biāo)):

訪問對(duì)象中數(shù)據(jù)的快捷方式

所謂下標(biāo)腳本語(yǔ)法就是能夠通過,實(shí)例[索引值]來(lái)訪問實(shí)例中的數(shù)據(jù)

類似于以前我們?cè)L問數(shù)字和字典,其實(shí)Swift中的數(shù)組和字典就是一個(gè)結(jié)構(gòu)體

structStudent {

varname:String="lzh"

varmath:Double=99.0

varchinese:Double=99.0

varenglish:Double=99.0

funcscore(course:String) ->Double?

{

switchcourse{

case"math":

returnmath

case"chinese":

returnchinese

case"english":

returnenglish

default:

returnnil

}

}

要想實(shí)現(xiàn)下標(biāo)訪問,必須實(shí)現(xiàn)subscript方法

如果想要通過下標(biāo)訪問,必須實(shí)現(xiàn)get方法

如果想要通過下表賦值,必須實(shí)現(xiàn)set方法

subscript(course:String) ->Double?{

get{

switchcourse{

case"math":

returnmath

case"chinese":

returnchinese

case"english":

returnenglish

default:

returnnil

}

}

set{

switchcourse{

case"math":

因?yàn)榉祷氐氖强蛇x類型

math= newValue!

case"chinese":

chinese= newValue!

case"english":

english= newValue!

default:

print("not found")

}

}

}

}

varstu =Student(name:"zs",

math:99.0,

chinese:88.0,

english:10.0)

print(stu.score("math"))

輸出結(jié)果:Optional(99.0)

stu["chinese"]=100.0

print(stu["chinese"])

輸出結(jié)果:Optional(100.0)



26-繼承,super關(guān)鍵字,override關(guān)鍵字,final關(guān)鍵字


繼承語(yǔ)法

繼承是面向?qū)ο笞铒@著的一個(gè)特性,繼承是從已經(jīng)有的類中派生出新的類

新的類能夠繼承已有類的屬性和方法,并能擴(kuò)展新的能力

術(shù)語(yǔ):基類(父類,超類),派生類(子類,繼承類)

語(yǔ)法:

class子類:父類{

}

繼承優(yōu)點(diǎn):代碼重用

繼承缺點(diǎn):增加程序耦合度,父類改變會(huì)影響子類

注意:Swift和OC一樣沒有多繼承

classMan {

varname:String="lzh"

varage:Int=10

funcsleep(){

print("睡覺")

}

}

classSuperMan:Man{

varpower:Int=100

funsfly(){

子類可以繼承父類的屬性

print("飛\(name)\(age)")

}

}

varm =Man()

m.sleep()

父類不可以使用子類的方法

m.fly()

輸出結(jié)果:睡覺

varsm =SuperMan()

子類可以繼承父類的方法

sm.sleep()

sm.fly()

輸出結(jié)果:

睡覺

飛lzh 10

super關(guān)鍵字:

派生類中可以通過super關(guān)鍵字來(lái)引用父類的屬性和方法

classMan {

varname:String="lzh"

varage:Int=30

funcsleep(){

print("睡覺")

}

}

classSuperMan:Man{

varpower:Int=100

funceat()

{

print("吃飯")

}

funcfly(){

子類可以繼承父類的屬性

print("飛\(super.name)\(super.age)")

}

funceatAndSleep()

{

eat()

super.sleep()

如果沒有寫super,那么會(huì)先在當(dāng)前類中查找,如果找不到再去父類中查找

如果寫了super,會(huì)直接去父類中查找

}

}

varsm =SuperMan()

sm.eatAndSleep()

輸出結(jié)果:

吃飯

睡覺

方法重寫: override

重寫父類方法,必須加上override關(guān)鍵字

classMan {

varname:String="lzh"

varage:Int=10

funcsleep(){

print("父類睡覺")

}

}

classSuperMan:Man{

varpower:Int=100

override關(guān)鍵字主要是為了明確表示重寫父類方法,

所以如果要重寫父類方法,必須加上override關(guān)鍵字

overridefuncsleep() {

sleep()不能這樣寫,會(huì)導(dǎo)致遞歸

super.sleep()

print("子類睡覺")

}

funceat()

{

print("吃飯")

}

funcfly(){

子類可以繼承父類的屬性

print("飛\(super.name)\(super.age)")

}

funceatAndSleep()

{

eat()

sleep()

}

}

varsm =SuperMan()

通過子類調(diào)用,優(yōu)先調(diào)用子類重寫的方法

sm.sleep()

輸出結(jié)果:

父類睡覺

子類睡覺

sm.eatAndSleep()

輸出結(jié)果:

吃飯

父類睡覺

子類睡覺

重寫屬性

無(wú)論是存儲(chǔ)屬性還是計(jì)算屬性,都只能重寫為計(jì)算屬性

classMan {

varname:String="lzh"存儲(chǔ)屬性

varage:Int{計(jì)算屬性

get{

return30

}

set{

print("man new age\(newValue)")

}

}

funcsleep(){

print("睡覺")

}

}

classSuperMan:Man{

varpower:Int=100

可以將父類的存儲(chǔ)屬性重寫為計(jì)算屬性

但不可以將父類的存儲(chǔ)屬性又重寫為存儲(chǔ)屬性,因?yàn)檫@樣沒有意義

override var name:String = "zs"

overridevarname:String{

get{

return"zs"

}

set{

print("SuperMan new name\(newValue)")

}

}

可以將父類的計(jì)算屬性重寫為計(jì)算屬性,同樣不能重寫為存儲(chǔ)屬性

overridevarage:Int{計(jì)算屬性

get{

return30

}

set{

print("superMan new age\(newValue)")

}

}

}

letsm =SuperMan()

通過子類對(duì)象來(lái)調(diào)用重寫的屬性或者方法,肯定會(huì)調(diào)用子類中重寫的版本

sm.name="xxx"

sm.age=50

輸出結(jié)果:

SuperMan new name xxx

superMan new age 50

重寫屬性的限制

1.讀寫計(jì)算屬性/存儲(chǔ)屬性,是否可以重寫為只讀計(jì)算屬性? (權(quán)限變小)不可以

2.只讀計(jì)算屬性,是否可以在重寫時(shí)變成讀寫計(jì)算屬性? (權(quán)限變大)可以

classMan {

varname:String="lzh"存儲(chǔ)屬性

varage:Int{計(jì)算屬性

get{

return30

}

set{

print("man new age\(newValue)")

}

}

funcsleep(){

print("睡覺")

}

}

classSuperMan:Man{

varpower:Int=100

overridevarname:String{

get{

return"zs"

}

set{

print("SuperMan new name\(newValue)")

}

}

overridevarage:Int{計(jì)算屬性

get{

return30

}

set{

print("superMan new age\(newValue)")

}

}

}

重寫屬性觀察器

只能給非lazy屬性的變量存儲(chǔ)屬性設(shè)定屬性觀察器,

不能給計(jì)算屬性設(shè)置屬性觀察器,給計(jì)算屬性設(shè)置屬性觀察器沒有意義

屬性觀察器限制:

1.不能在子類中重寫父類只讀的存儲(chǔ)屬性

2.不能給lazy的屬性設(shè)置屬性觀察器

classMan {

varname:String="lzh"

varage:Int=0{存儲(chǔ)屬性

willSet{

print("super new\(newValue)")

}

didSet{

print("super new\(oldValue)")

}

}

varheight:Double{

get{

print("super get")

return10.0

}

set{

print("super set")

}

}

}

classSuperMan:Man{

可以在子類中重寫父類的存儲(chǔ)屬性為屬性觀察器

overridevarname:String{

willSet{

print("new\(newValue)")

}

didSet{

print("old\(oldValue)")

}

}

可以在子類中重寫父類的屬性觀察器

overridevarage:Int{

willSet{

print("child new\(newValue)")

}

didSet{

print("child old\(oldValue)")

}

}

可以在子類重寫父類的計(jì)算屬性為屬性觀察器

overridevarheight:Double{

willSet{

print("child height")

}

didSet{

print("child height")

}

}

}

varm =SuperMan()

m.age=55

輸出結(jié)果:

child new 55

super new 55

super new 0

child old 0

print(m.age)

輸出結(jié)果:55

m.height=20.0

輸出結(jié)果:

super get

child height

super set

child height

final關(guān)鍵字

利用final關(guān)鍵字防止重寫

final關(guān)鍵字既可以修飾屬性,也可以修飾方法,并且還可以修飾類

被final關(guān)鍵字修飾的屬性和方法不能被重寫

被final關(guān)鍵字修飾的類不能被繼承

finalclassMan {

finalvarname:String="lzh"

finalvarage:Int=0{//存儲(chǔ)屬性

willSet{

print("super new\(newValue)")

}

didSet{

print("super new\(oldValue)")

}

}

finalvarheight:Double{

get{

print("super get")

return10.0

}

set{

print("super set")

}

}

finalfunceat(){

print("吃飯")

}

}



27- 構(gòu)造方法,帶參數(shù)的構(gòu)造方法,常量存儲(chǔ)屬性與構(gòu)造方法,結(jié)構(gòu)體構(gòu)造方法


構(gòu)造方法

作用:對(duì)實(shí)例對(duì)象的內(nèi)容進(jìn)行初始化

Swift要求類或者結(jié)構(gòu)體中的存儲(chǔ)屬性(非lazy的)在對(duì)象構(gòu)造完畢后要有初始化值

語(yǔ)法:

init(參數(shù)列表){初始化代碼}

注意:

1.在Swift中類/結(jié)構(gòu)體/枚舉都需要構(gòu)造方法

2.構(gòu)造方法的作用僅僅是用于初始化屬性,而不是分配內(nèi)容,分配內(nèi)存是系統(tǒng)幫我們做的

3.構(gòu)造方法是隱式調(diào)用的,通過類名稱()形式創(chuàng)建一個(gè)對(duì)象就會(huì)隱式調(diào)用init()構(gòu)造方法

4.如果所有的存儲(chǔ)屬性都有默認(rèn)值,可以不提供構(gòu)造方法,系統(tǒng)會(huì)提供一個(gè)隱式的構(gòu)造方法

5.如果存儲(chǔ)屬性可以提供缺省,那么提倡大家使用設(shè)置缺省值的方式,

這樣可以簡(jiǎn)化代碼(不用自定義構(gòu)造方法,不用寫存儲(chǔ)屬性類型)

classPerson {

varname:String="lzh"

varage:Int

funcdescription() ->String{

return"name =\(name) age =\(age)"

}

init()

{

print("init")

age=30

}

}

1.分配內(nèi)存

2.初始化name和age

3.構(gòu)造方法是隱式調(diào)用的

varp =Person()

p.description()顯示調(diào)用

輸出結(jié)果:init

帶參數(shù)的構(gòu)造方法

classPerson {

varname:String

varage:Int

funcdescription() ->String{

return"name =\(name) age =\(age)"

}

構(gòu)造方法的內(nèi)部參數(shù),默認(rèn)也是外部參數(shù)

而函數(shù)的內(nèi)部參數(shù)默認(rèn)不會(huì)當(dāng)做外部參數(shù)

而方法的內(nèi)部參數(shù),從第二個(gè)開始才會(huì)當(dāng)做外部參數(shù)

init(name:String, age:Int)

構(gòu)造方法對(duì)屬性的順序沒有要求,

只要保證對(duì)象構(gòu)造完時(shí)所有存儲(chǔ)屬性被初始化即可

init(age:Int, name:String)

{

self.name= name

self.age= age

}

funcsetName(name:String, age:Int)

{

}

}

varp =Person(age:30, name:"lzh")

p.setName("lzh", age:30)

funcsetName(name:String, age:Int)

{

}

p.setName("lzh", age:30)

常量存儲(chǔ)屬性與構(gòu)造方法

常量存儲(chǔ)屬性只能通過缺省值或在構(gòu)造方法中被修改

其它任何地方都不能修改

classPerson {

varname:String="lzh"

letage:Int

init(age:Int, name:String)

{

self.age= age

self.name= name

}

funcdescription() ->String{

return"name =\(name) age =\(age)"

}

}

varp =Person(age:30, name:"zs")

print(p3.description())

輸出結(jié)果:name = zs age = 30

常量存儲(chǔ)屬性初始化之后不允許被修改

p.age =10

可選屬性與構(gòu)造方法

classCar {

letname:String

init(name:String)

{

self.name= name

}

}

classPerson {

letname:String

varage:Int

varcar:Car?

可選值存儲(chǔ)屬性可以不再構(gòu)造方法中初始化,

也就是說可選值在對(duì)象構(gòu)造完畢后不用初始化

其實(shí)如果不對(duì)可選存儲(chǔ)屬性進(jìn)行初始化,默認(rèn)就是nil

init(age:Int, name:String)

{

self.age= age

self.name= name

}

funcdescription() ->String{

return"name =\(name) age =\(age) car =\(car)"

}

}

varp =Person(age:10, name:"lzh")

print(p.description())

輸出結(jié)果:name = lzh age = 10 car = nil

結(jié)構(gòu)體構(gòu)造方法

structRect{

此時(shí)即沒有提供缺省值,也沒有提供構(gòu)造方法,但是編譯通過

因?yàn)槟J(rèn)情況下,結(jié)構(gòu)體會(huì)給結(jié)構(gòu)體提供一個(gè)默認(rèn)的成員逐一構(gòu)造器

varwidth:Double=0.0

varheight:Double=0.0

系統(tǒng)默認(rèn)會(huì)提供一個(gè)類似的方法

init(width:Double, height:Double)

{

self.width = width

self.height = height

}

init()

{

self.width = 0.0

self.height = 0.0

}

}

注意:

1.在類中默認(rèn)是沒有逐一構(gòu)造器的

2.如果在結(jié)構(gòu)體中自定義了構(gòu)造方法,那么系統(tǒng)不會(huì)生成默認(rèn)的逐一構(gòu)造器

3.如果給存儲(chǔ)屬性提供了缺省值,系統(tǒng)還是會(huì)提供默認(rèn)的逐一構(gòu)造器

4.如果給存儲(chǔ)屬性提供了缺省值,可以使用不帶參數(shù)的方法初始化結(jié)構(gòu)體

varr =Rect()

print("width=\(r.width),height=\(r.height)")

輸出結(jié)果:width=0.0,height=0.0

varr =Rect(width:10, height:20)

print("width=\(r.width),height=\(r.height)")

輸出結(jié)果:width=10.0,height=20.0

"值類型"的構(gòu)造器代理

構(gòu)造器代理:構(gòu)造方法之間的相互調(diào)用

構(gòu)造方法可以調(diào)用其他構(gòu)造方法來(lái)完成實(shí)例的構(gòu)造,稱之為構(gòu)造器代理

好處:減少構(gòu)造方法之間的重復(fù)代碼

structRect {

varwidth:Double

varheight:Double

init(width:Double, height:Double)

{

self.width= width

self.height= height

}

init()

{

self.width = 0

self.height = 0

構(gòu)造器代理

self.init(width:0, height:0)

}

funcshow(){

print("width =\(width) height =\(height)")

}

}

varr =Rect()

r.show()

輸出結(jié)果:width = 0.0 height = 0.0

varr1 =Rect(width:100, height:100)

r1.show()

輸出結(jié)果:

width = 100.0 height = 100.0

通過閉包或者全局函數(shù)/類方法設(shè)置存儲(chǔ)屬性的缺省值

如果需要經(jīng)過計(jì)算,或者需要進(jìn)行一些額外的操作才能確定初始值時(shí)

就可以通過閉包或全局函數(shù)設(shè)置存儲(chǔ)屬性的缺省值

funcgetValue() ->Int

{

print("getValue")

return55

}

classPerson {

varname:String

系統(tǒng)在初始化的時(shí)候會(huì)隱式執(zhí)行閉包,

將閉包的執(zhí)行結(jié)果賦值給存儲(chǔ)屬性

注意:閉包后面一定要有(),代表執(zhí)行閉包

varage:Int= {

() -> Int in返回值可以省略,

默認(rèn)返回值的類型就是存儲(chǔ)屬性的類型

print("age閉包")

return30

}()

lazyvarheight:Double= {

print("lazy閉包")

return175.0

}()

varage2:Int=getValue()

varage3:Int=Person.getValue2()

不能這樣寫,因?yàn)檎{(diào)用方法時(shí)對(duì)象還沒有初始化完畢

self只有當(dāng)所有的存儲(chǔ)屬性都初始化完畢之后才可以用

var age3:Int = self.getValue3()

init(name:String)

{

print("init")

self.name= name

}

classfuncgetValue2() ->Int{

print("class getValue2")

return100

}

funcgetValue3() ->Int

{

return88

}

}

varp =Person(name:"lzh")

懶加載是用到時(shí)才執(zhí)行,而閉包賦值是初始化時(shí)就會(huì)執(zhí)行

print(p.height)

輸出結(jié)果:

age閉包

getValue

class getValue2

init

lazy閉包

175.0



28- 繼承與構(gòu)造方法, 指定構(gòu)造與便利構(gòu)造方法


指定構(gòu)造與便利構(gòu)造方法

classPerson {

varname:String

varage:Int

指定構(gòu)造方法都是以init開頭的

init(name:String, age:Int)

{

print("init")

self.name= name

self.age= age

}

如果是值類型沒問題,稱之為構(gòu)造器代理

但如果是引用類型會(huì)報(bào)錯(cuò),需要在前面加上convenience關(guān)鍵字.

被convenience關(guān)鍵字修飾的構(gòu)造方法稱之為便利構(gòu)造器,

通過調(diào)用其它構(gòu)造方法來(lái)初始化.

反而言之,便利構(gòu)造器中一定是調(diào)用其它構(gòu)造方法初始化的

一定要出現(xiàn)self.init

convenienceinit()

{

print("convenience init")

self.init(name:”lzh", age:30)

}

類可以擁有多個(gè)構(gòu)造方法

init(name:String)

{

print("init name")

self.name= name

self.age=0

不能在指定構(gòu)造方法中調(diào)用便利構(gòu)造方法

也就是說指定構(gòu)造方法中不能出現(xiàn)self.init

self.init()

}

convenienceinit(age:Int)

{

print("convenience init age")

可以在便利構(gòu)造器中調(diào)用指定構(gòu)造器

self.init(name:”lzh", age:30)

以在便利構(gòu)造器中調(diào)用便利構(gòu)造器

self.init()

}

便利構(gòu)造器不能和指定構(gòu)造器同名

convenience init(name:String)

{

}

}

varp =Person()

輸出結(jié)果:

convenience init

init

varp1 =Person(age:10)

輸出結(jié)果:

convenience init age

convenience init

init

varp2 =Person(name:"lzh")

輸出結(jié)果:

init name

varp3 =Person(name:"lzh", age:20)

輸出結(jié)果:

init

派生類的構(gòu)造方法

classMan {

varname:String

指定構(gòu)造方法

init(name:String){

print("Man init")

self.name= name

}

便利構(gòu)造方法

convenienceinit(){

print("Man convenience init")

self.init(name:"convenience-lzh")

}

}

classSuperMan:Man{

varage:Int

注意:

1.默認(rèn)情況下構(gòu)造方法不會(huì)被繼承

2.基類的存儲(chǔ)屬性只能通過基類的構(gòu)造方法初始化

3.初始化存儲(chǔ)屬性時(shí)必須先初始化當(dāng)前類再初始化父類

4.不能通過便利構(gòu)造方法初始化父類,只能通過調(diào)用指定構(gòu)造方法初始化父類

指定構(gòu)造器

init(age:Int){

self.age= age

super.init(name:"lzh")

不能通過便利構(gòu)造方法初始化父類,只能通過調(diào)用指定構(gòu)造方法初始化父類

以下寫法是錯(cuò)誤的

super.init()

}

funcshow(){

print("age =\(self.age) name=\(self.name)")

}

}

varp =Man()

輸出結(jié)果:

Man convenience init

Man init

varp =SuperMan(age:10)

輸出結(jié)果:

SuperMan init

Man init

構(gòu)造器間的調(diào)用規(guī)則

>指定構(gòu)造器必須調(diào)用其直接父類的"指定構(gòu)造器"

>便利構(gòu)造器必須調(diào)用同類中的其它構(gòu)造器(指定或便利)

>便利構(gòu)造器必須最終以調(diào)用一個(gè)指定構(gòu)造器結(jié)束

(無(wú)論調(diào)用的是指定還是便利,最終肯定會(huì)調(diào)用一個(gè)指定構(gòu)造器)

*指定構(gòu)造器總是向上代理(父類)

*便利構(gòu)造器總是橫向代理(當(dāng)前類)

classMan {

varname:String

指定構(gòu)造方法

init(name:String){

print("Man->init")

self.name= name

}

便利構(gòu)造方法

convenienceinit(){

print("Man->convenience init")

self.init(name:"lzh")

}

}

classSuperMan:Man{

varage:Int

指定構(gòu)造器

init(age:Int){

print("SuperMan->init")

self.age= age

super.init(name:"lzh")

}

convenienceinit(){

print("SuperMan->convenience init")

self.init(age:30)

}

convenienceinit(name:String, age:Int){

print("SuperMan->convenience init name age")

調(diào)用子類構(gòu)造器一定能夠初始化所有屬性

便利構(gòu)造器中只能通過self.init來(lái)初始化,不能使用super.init

因?yàn)檎{(diào)用父類構(gòu)造器不一定能完全初始化所有屬性(子類特有)

super.init(name: “l(fā)zh")

self.init()

}

funcshow(){

print("name =\(self.name) age =\(self.age)")

}

}

varp =SuperMan()

p.show()

輸出結(jié)果:

SuperMan->convenience init

SuperMan->init

Man->init

name = lzh age = 30

varp =SuperMan(age:10)

p.show()

輸出結(jié)果:

SuperMan->init

Man->init

name = lzh age = 10

varp =SuperMan(name:"lzh", age:20)

p.show()

輸出結(jié)果:

SuperMan->convenience init name age

SuperMan->convenience init

SuperMan->init

Man->init

name = lzh age = 30

兩段式構(gòu)造

構(gòu)造過程可以劃分為兩個(gè)階段

1.確保當(dāng)前類和父類所有存儲(chǔ)屬性都被初始化

2.做一些其它初始化操作

好處: 1.可以防止屬性在被初始化之前訪問

2.可以防止屬性被另外一個(gè)構(gòu)造器意外賦值

注意:構(gòu)造器的初始化永遠(yuǎn)是在所有類的第一階段初始化完畢之后才會(huì)開始第二階段

編譯器安全檢查:

1.必須先初始化子類特有屬性,再向上代理父類指定構(gòu)造方法初始化父類屬性

2.只能在調(diào)用完父類指定構(gòu)造器后才能訪問父類屬性

3.在便利構(gòu)造器中,必須先調(diào)用同類其它構(gòu)造方法后才能訪問屬性

4.第一階段完成前不能訪問父類屬性/也不能引用self和調(diào)用任何實(shí)例方法

classMan {

varname:String

指定構(gòu)造方法

init(name:String){

self.name= name

}

便利構(gòu)造方法

convenienceinit(){

self.init(name:"lnj")

}

}

classSuperMan:Man{

varage:Int

指定構(gòu)造器

init(age:Int){

print("SuperMan第一階段開始")

對(duì)子類引入的屬性初始化

self.age= age

代碼會(huì)報(bào)錯(cuò),因?yàn)檎{(diào)用self.name之前還沒有對(duì)父類的name進(jìn)行初始化

即便在這個(gè)地方修改,也會(huì)被后面的初始化語(yǔ)句覆蓋

if (age > 30){

self.name = "zs"

}

對(duì)父類引入的屬性進(jìn)行初始化

super.init(name:"lzh")

print("SuperMan第二階段開始")

ifage >30{

self.name="zs"

}

}

}

classMonkeyMan:SuperMan{

varheight:Double

init(height:Double){

print("MonkeyMan第一階段開始")

對(duì)子類引入的屬性初始化

self.height=99.0

對(duì)父類引入的屬性進(jìn)行初始化

super.init(age:30)

print("MonkeyMan第二階段開始")

ifheight <100.0{

self.age=50

}

}

}

varm =MonkeyMan(height:20)

輸出結(jié)果:

MonkeyMan第一階段開始

SuperMan第一階段開始

SuperMan第二階段開始

MonkeyMan第二階段開始

重寫指定構(gòu)造方法

子類的構(gòu)造方法和父類的一模一樣

classMan {

varname:String

指定構(gòu)造方法

init(name:String){

self.name= name

}

}

classSuperMan:Man{

varage:Int

init(){

self.age=30

super.init(name:“l(fā)zh")

}

如果子類中的構(gòu)造器和父類一模一樣

必須加上override關(guān)鍵字,表示重寫父類方法

在老版本的Swift語(yǔ)言中是不需要override關(guān)鍵字的,新版本才推出的

override init(name:String){

self.age = 30

super.init(name: name)

}

將父類的指定構(gòu)造器重寫成一個(gè)便利構(gòu)造器

也必須加上override關(guān)鍵字,表示重寫父類方法

convenienceoverrideinit(name:String){

self.init(name:name)

self.age=30

}

}

varp =SuperMan()

輸出結(jié)果:

SuperMan init

Man init

便利構(gòu)造方法不存在重寫

classMan {

varname:String

指定構(gòu)造方法

init(name:String){

print("Man->init")

self.name= name

}

convenienceinit(){

print("Man->convenience init")

self.init(name:"lzh")

}

}

classSuperMan:Man{

varage:Int

init(age:Int){

print("SuperMan->init")

self.age= age

super.init(name:"lzh")

}

Swift中便利構(gòu)造方法不存在重寫,如果加上override關(guān)鍵字

系統(tǒng)會(huì)去查找父類中有沒有和便利構(gòu)造方法一樣的指定構(gòu)造方法

有就不報(bào)錯(cuò),沒有就報(bào)錯(cuò)

為什么便利構(gòu)造器不能重寫呢?

因?yàn)楸憷麡?gòu)造器只能橫向代理

只能調(diào)用當(dāng)前類的其它構(gòu)造方法或指定方法,不可能調(diào)用super.所以不存在重寫

也就是說子類的便利構(gòu)造方法不能直接訪問父類的便利構(gòu)造方法,所以不存在重寫的概念

convenienceinit(){

print("SuperMan-> convenience init")

self.init(age:30)

}

}

varsm =SuperMan()

輸出結(jié)果:

SuperMan-> convenience init

SuperMan->init

Man->init

構(gòu)造方法的自動(dòng)繼承

1.如果子類中沒有定義任何構(gòu)造器,且子類中所有的存儲(chǔ)屬性都有缺省值,

會(huì)繼承父類中所有的構(gòu)造方法(包括便利構(gòu)造器)

2.如果子類中只是重寫了父類中的某些指定構(gòu)造器

不管子類中的存儲(chǔ)屬性是否有缺省值,都不會(huì)繼承父類中的其它構(gòu)造方法

3.如果子類重寫了父類中所有的指定構(gòu)造器

不管子類中的存儲(chǔ)屬性是否有缺省值,都會(huì)同時(shí)繼承父類中的所有便利方法

classPerson {

varname:String

varage:Int

init(name:String, age:Int){

print("Person init name age")

self.name= name

self.age= age

}

init(name:String){

print("Person init name")

self.name= name

self.age=0

}

convenienceinit(){

print("Person convenience init")

self.init(name:"lzh")

}

}

classSuperMan:Person{

varheight:Double=175.0

}

如果子類中沒有定義任何構(gòu)造器,

且子類中所有的存儲(chǔ)屬性都有缺省值,會(huì)繼承父類中所有的構(gòu)造方法(包括便利構(gòu)造器).

父類的存儲(chǔ)屬性是由父類的構(gòu)造器初始化,子類的存儲(chǔ)屬性是由缺省值初始化的.

varp =SuperMan()

如果子類中只是重寫了父類中的某些指定構(gòu)造器

不管子類中的存儲(chǔ)屬性是否有缺省值,都不會(huì)繼承父類中的其它構(gòu)造方法

classSuperMan:Person{

varheight:Double=175.0

init(height:Double){

self.height= height

super.init(name:“l(fā)zh", age:30)

}

}

varp =SuperMan()

如果子類重寫了父類中所有的指定構(gòu)造器

不管子類中的存儲(chǔ)屬性是否有缺省值,都會(huì)同時(shí)繼承父類中的所有便利方法

classSuperMan:Person{

varheight:Double

init(height:Double){

self.height= height

super.init(name:"lzh", age:30)

}

overrideinit(name:String, age:Int){

self.height=175.0

super.init(name: name, age: age)

}

overrideinit(name:String){

self.height=175.0

super.init(name: name)

}

}

必須構(gòu)造器

只要在構(gòu)造方法的前面加上一個(gè)required關(guān)鍵字

那么所有的子類(后續(xù)子類)只要定義了構(gòu)造方法都必須實(shí)現(xiàn)該構(gòu)造方法

classPerson {

varname:String

早期Swift版本中沒有這個(gè)語(yǔ)法

requiredinit(name:String){

print("Person init")

self.name= name

}

}

classSuperMan:Person{

varage:Int=30

如果子類沒有定義構(gòu)造器,可以不用重寫

init(){

print("SuperMan init")

self.age=30

super.init(name:"lzh")

}

1.如果子類自定義了構(gòu)造器,就必須重寫"必須構(gòu)造器"

因?yàn)槿绻宇悰]有自定義任何構(gòu)造器,默認(rèn)會(huì)繼承父類構(gòu)造器,所以不用重寫

2.重寫必須構(gòu)造器不用加override關(guān)鍵字

因?yàn)橄到y(tǒng)看到required關(guān)鍵字就會(huì)自動(dòng)查看父類

為什么重寫了還需要加上required關(guān)鍵字,因?yàn)樗泻罄m(xù)子類都必須重寫

requiredinit(name:String) {

print("SuperMan init name")

self.age=30

super.init(name:name)

}

}

varsm =SuperMan(name:"lzh")

輸出結(jié)果:

SuperMan init name

Person init



29- 析構(gòu)方法


析構(gòu)方法

對(duì)象的內(nèi)存被回收前夕被隱式調(diào)用的方法,對(duì)應(yīng)OC的dealloc方法

主要執(zhí)行一些額外操作,例如釋放一些持有資源,關(guān)閉文件,斷開網(wǎng)絡(luò)等

classFileHandler{

varfd:Int32?文件描述符

指定構(gòu)造器

init(path:String){

需要打開的文件路徑,打開方式(只讀)

open方法是UNIX的方法

letret =open(path,O_RDONLY)

ifret == -1{

fd=nil

}else{

fd= ret

}

print("對(duì)象被創(chuàng)建")

}

析構(gòu)方法

deinit{

關(guān)閉文件

ifletofd =fd{

close(ofd)

}

print("對(duì)象被銷毀")

}

}

varfh:FileHandler? =

FileHandler(path:"/Users/gaoxinqiang/Desktop/lzh.jpg")

當(dāng)對(duì)象沒有任何強(qiáng)引用時(shí)會(huì)被銷毀

fh=nil

輸出結(jié)果:

對(duì)象被創(chuàng)建

對(duì)象被銷毀

析構(gòu)方法的自動(dòng)繼承

父類的析構(gòu)方法會(huì)被自動(dòng)調(diào)用,不需要子類管理

classPerson {

varname:String

init(name:String){

self.name= name

print("Person init")

}

deinit{

print("Person deinit")

}

}

classSuperMan:Person{

varage:Int

init(age:Int){

self.age= age

super.init(name:"xmg")

print("SuperMan init")

}

deinit{

如果父類的析構(gòu)方法不會(huì)被自動(dòng)調(diào)用,那么我們還需要關(guān)心父類

但是如果這樣做對(duì)子類是比較痛苦的

print("SuperMan deinit")

}

}

varsm:SuperMan? =SuperMan(age:30)

sm=nil

輸出結(jié)果:

Person init

SuperMan init

SuperMan deinit

Person deinit


30- Swift內(nèi)存管理


Swift內(nèi)存管理:

管理引用類型的內(nèi)存,不會(huì)管理值類型,值類型不需要管理

內(nèi)存管理原則:當(dāng)沒有任何強(qiáng)引用指向?qū)ο?系統(tǒng)會(huì)自動(dòng)銷毀對(duì)象

(默認(rèn)情況下所有的引用都是強(qiáng)引用)

如果做到該原則: ARC

classPerson {

varname:String

init(name:String){

self.name= name

}

deinit{

print("deinit")

}

}

varp:Person? =Person(name:"xmg")

p=nil

輸出結(jié)果:deinit

weak弱引用

classPerson {

varname:String

init(name:String){

self.name= name

}

deinit{

print("deinit")

}

}

強(qiáng)引用,引用計(jì)數(shù)+1

varstrongP =Person(name:"xmg")1

varstrongP2 =strongP2

弱引用,引用計(jì)數(shù)不變

如果利用weak修飾變量,當(dāng)對(duì)象釋放后會(huì)自動(dòng)將變量設(shè)置為nil

所以利用weak修飾的變量必定是一個(gè)可選類型,因?yàn)橹挥锌蛇x類型才能設(shè)置為nil

weakvarweakP:Person? =Person(name:"xmg")

ifletp =weakP{

print(p)

}else

{

print(weakP)

}

輸出結(jié)果:

deinit

nil

unowned無(wú)主引用,相當(dāng)于OC unsafe_unretained

unowned和weak的區(qū)別:

1.利用unowned修飾的變量,對(duì)象釋放后不會(huì)設(shè)置為nil.不安全

利用weak修飾的變量,對(duì)象釋放后會(huì)設(shè)置為nil

2.利用unowned修飾的變量,不是可選類型

利用weak修飾的變量,是可選類型

classPerson {

varname:String

init(name:String){

self.name= name

}

deinit{

print("deinit")

}

}

unownedvarweakP:Person=Person(name:"xmg")

循環(huán)引用

ARC不是萬(wàn)能的,它可以很好的解決內(nèi)存問題,但是在某些場(chǎng)合不能很好的解決內(nèi)存泄露問題

例如兩個(gè)或多個(gè)對(duì)象之間的循環(huán)引用問題

classPerson {

letname:String姓名

人不一定有公寓

如果這里不加weak的話,當(dāng)對(duì)象設(shè)置為nil時(shí),該對(duì)象并沒有被銷毀.

weakvarapartment:Apartment?公寓

init(name:String){

self.name= name

}

deinit{

print("\(self.name) deinit")

}

}

classApartment {

letnumber:Int房間號(hào)

vartenant:Person?租客

init(number:Int){

self.number= number

}

deinit{

print("\(self.number) deinit")

}

}

varp:Person? =Person(name:"xmg")

vara:Apartment? =Apartment(number:888)

p!.apartment=a人有一套公寓

a!.tenant=p!公寓中住著一個(gè)人

p=nil

a=nil

輸出結(jié)果:

888 deinit

xmg deinit

classPerson {

letname:String姓名

人不一定有信用卡

varcard:CreditCard?

init(name:String){

self.name= name

}

deinit{

print("\(self.name) deinit")

}

}

classCreditCard{

letnumber:Int

信用卡必須有所屬用戶

當(dāng)某一個(gè)變量/常量必須有值,一直有值,那么可以使用unowned修飾

unownedletperson:Person

init(number:Int, person:Person){

self.number= number

self.person= person

}

deinit{

print("\(self.number) deinit")

}

}

varp:Person? =Person(name:"xmg")

varcc:CreditCard? =CreditCard(number:8888888, person:p!)

p=nil

cc=nil

輸出結(jié)果:

xmg deinit

8888888 deinit


31- swift可選類型


可選類型:

可選類型的本質(zhì)其實(shí)就是一個(gè)枚舉

None沒有值

Some有值

格式: Optional<類型>或在類型后面加上?號(hào)

由于可選類型在Swift中隨處可見,所以系統(tǒng)做了一個(gè)語(yǔ)法糖,在類型后面加上?

varopa:Optional

varopb:Int?

varnora:Int

nora=10

print(nora)

print(opb)

輸出結(jié)果:

10

nil

基本類型變量,在使用之前必須進(jìn)行初始化,否則報(bào)錯(cuò)

目的:安全,不管在什么時(shí)候訪問都是有意義的

普通變量和可選類型的區(qū)別,普通變量只有一種狀態(tài),有值

注意:Swift的變量和C/OC的不一樣, C/OC可以沒有值,是一個(gè)隨機(jī)值

可選類型是安全的么?是,可以通過可選綁定判斷后再使用

Swift的發(fā)明者完全是基于安全的考慮,當(dāng)我們使用基本類型時(shí)完全不用考慮是否有值

當(dāng)我們使用可選類型時(shí),總會(huì)記得先判斷再使用.讓程序時(shí)刻了解哪些有值哪有沒有值

varopb:Int?

opb=55

ifletb =opb{

print(opb!)

print(b)

}

輸出結(jié)果:

55

55

可選鏈

通過可選類型的變量來(lái)調(diào)用相應(yīng)的屬性和方法

可選鏈的返回值是一個(gè)可選值

格式:

可選值?.屬性

可選值?.方法

classPerson {

varname:String

init(name:String){

self.name= name

}

funcwhoami() ->String{

print("my name is\(self.name)")

returnname

}

}

varp0 :Person?

varp1 :Person=Person(name:"xmg")

p1.name="zs"

p1.whoami()

輸出結(jié)果:

my name is zs

如何通過可選類型來(lái)調(diào)用對(duì)應(yīng)的方法和屬性

1.通過強(qiáng)制解包

但是強(qiáng)制解包非常危險(xiǎn),如果可選類型沒有值,會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤

p0!.name="ls"

p0!.whoami()

2.通過可選綁定,代碼繁瑣

ifletp =p0{

p.name="ls"

p.whoami()

}

3.通過可選鏈,如果問號(hào)前面的變量沒有值,整個(gè)可選鏈會(huì)失效

p0=p1

p0?.name="ls"

p0?.whoami()

可選鏈的返回值會(huì)自動(dòng)包裝成一個(gè)可選值

因?yàn)榭蛇x鏈可用能失效

所以返回值可能有值也可能沒有值

要想表達(dá)有值或者沒有值只能用可選值,所以返回值會(huì)自動(dòng)包裝成一個(gè)可選值

print(p0?.name)

print(p0?.whoami())

print(p1.name)

vara:String? =p0?.name

p0?.name="ww"

varb:String=p1.name

輸出結(jié)果:

nil

nil

xmg

可選鏈調(diào)用下標(biāo)索引

格式:

可選值?[]

structStudent {

varname:String="xmg"

varmath:Double=99.0

varchinese:Double=99.0

varenglish:Double=99.0

要想實(shí)現(xiàn)下標(biāo)訪問,必須實(shí)現(xiàn)subscript方法

如果想要通過下標(biāo)訪問,必須實(shí)現(xiàn)get方法

如果想要通過下表賦值,必須實(shí)現(xiàn)set方法

subscript(course:String) ->Double?{

get{

switchcourse{

case"math":

returnmath

case"chinese":

returnchinese

case"english":

returnenglish

default:

returnnil

}

}

set{

switchcourse{

case"math":

因?yàn)榉祷氐氖强蛇x類型

math= newValue!

case"chinese":

chinese= newValue!

case"english":

english= newValue!

default:

print("not found")

}

}

}

}

varstu:Student? =Student()

可選鏈調(diào)用下標(biāo)索引不需要.,直接在問號(hào)后面寫上[]即可

print(stu?["math"])

輸出結(jié)果:Optional(99.0)

利用可選鏈賦值.注意:早起版本中不能利用可選鏈賦值

stu?.name="ww"

print(stu?.name)

輸出結(jié)果:Optional("ww")

利用可選鏈給下標(biāo)賦值

stu?["math"]=88

print(stu?["math"])

輸出結(jié)果:Optional(88.0)

判斷賦值操作是否成功,可選鏈的賦值操作也有返回值

如果賦值成功會(huì)返回一個(gè)可選類型

返回()?也就是Viod?代表成功.

返回nil代表失敗

letres:Void? =stu?.name="zl"

print(res)

輸出結(jié)果:Optional(())代表成功.

stu=nil

letres:Void? =stu?.name="zl"

print(res)

輸出結(jié)果:nil代表失敗

多層可選鏈:

單層:可選值?.屬性

多層:可選值?.屬性.屬性?.屬性或者可選值?.屬性?.屬性?.屬性

classA {

varname:String="xmg"

}

classB{

vara1:A?

}

classC{

varb1:B=B()

}

classD{

varc1:C?

}

vara1 =A()

varb1 =B()

varc1 =C()

vard1 =D()

d1.c1=c1

通過d直接給b賦值

由于D中的C是可選值,所以需要在C后面加上?

d1.c1?.b1.a1=a1

通過d直接獲取a中的name

其實(shí)只需要在可選值后面加上問號(hào)即可,如果可選值不存在,那么后面的鏈?zhǔn)?/p>

print(d1.c1?.b1.a1?.name)

輸出結(jié)果:Optional("xmg")

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兽赁,一起剝皮案震驚了整個(gè)濱河市擂达,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖抗果,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異免都,居然都是意外死亡驯妄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門号涯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)目胡,“玉大人,你說我怎么就攤上這事链快∮海” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵域蜗,是天一觀的道長(zhǎng)巨双。 經(jīng)常有香客問我,道長(zhǎng)霉祸,這世上最難降的妖魔是什么筑累? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮丝蹭,結(jié)果婚禮上慢宗,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好婆廊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布迅细。 她就那樣靜靜地躺著,像睡著了一般淘邻。 火紅的嫁衣襯著肌膚如雪茵典。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天宾舅,我揣著相機(jī)與錄音统阿,去河邊找鬼。 笑死筹我,一個(gè)胖子當(dāng)著我的面吹牛扶平,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔬蕊,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼结澄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了岸夯?” 一聲冷哼從身側(cè)響起麻献,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎猜扮,沒想到半個(gè)月后勉吻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旅赢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年齿桃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片煮盼。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡短纵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出僵控,到底是詐尸還是另有隱情,我是刑警寧澤养渴,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布泛烙,位于F島的核電站蔽氨,受9級(jí)特大地震影響帆疟,放射性物質(zhì)發(fā)生泄漏踪宠。R本人自食惡果不足惜柳琢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望润脸。 院中可真熱鬧柬脸,春花似錦、人聲如沸毙驯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)爆价。三九已至垦巴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铭段,已是汗流浹背骤宣。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稠项,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓鲜结,卻偏偏與公主長(zhǎng)得像展运,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子精刷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容