Swift 繼承、初始化器⑨

?????

1. 繼承的簡單介紹

  • 值類型(枚舉舔亭、結(jié)構(gòu)體)不支持繼承些膨。只有類支持繼承
  • 沒有父類的類,稱為:基類 分歇;Swift中沒有OC傀蓉、Java那樣的規(guī)定,所有類最終都要繼承自某個基類
  • 子類可以重寫父類的下標(biāo)职抡、方法葬燎、屬性,重寫必須加上override關(guān)鍵字

1.1 重寫實(shí)例方法缚甩、下標(biāo)

class Animal {
    func speak() {
        print("Animal Speak")
    }
    subscript(index: Int)-> Int{
        get{
            return index
        }
    }
}

class Dog: Animal {
    override func speak() {
        super.speak()
        print("Dog Speak")
    }
    override subscript(index: Int) -> Int {
        get{
            return super[index] + 1
        }
    }
}

class ErHa: Dog {
    var iq = 0
}
var ani = Animal()
var d = Dog()

ani.speak()
print("Ani:",ani[1])
print("================")
d.speak()
print("Dog:",d[1])
print("================")

打印結(jié)果:

Animal Speak
Ani: 1
================
Animal Speak
Dog Speak
Dog: 2
================

注意:

  • 父類指針指向子類對象時谱净,就是多態(tài),在調(diào)用時擅威,調(diào)用的是指針指向?qū)ο蟮姆椒?/li>
  • class修飾的類型方法壕探、下標(biāo)允許】被子類重寫
  • static修飾的類型方法下標(biāo)不允許】被子類重寫

1.2 重寫實(shí)例屬性

  • 子類可以將父類的屬性(存儲郊丛、計(jì)算)重寫為計(jì)算屬性
  • 子類不可以將父類屬性重寫為存儲屬性
  • 子類只能重寫父類的var屬性李请,不能重寫let屬性
  • 重寫時,屬性名厉熟、類型要一致
  • 子類重寫后的權(quán)限不能小于父類屬性的權(quán)限
    1. 如果父類是只讀的导盅,那么子類重寫后的屬性可以是只讀的、也可以是讀寫的
    2. 如果父類是讀寫的揍瑟,那么子類重寫后的屬性也必須是可讀寫的

實(shí)例:

class Circle {
    var radius: Int = 0
    var diameter: Int{
        set{
            print("Circle setDiameter")
            radius = newValue / 2
        }
        get{
            print("Circle getDiameter")
           return radius * 2
        }
    }
}

class SubSircle: Circle {
    override var radius: Int {
        set{
            print("SubSircle setRadius")
            super.radius = newValue > 0 ? newValue : 0
        }
        get{
            print("SubSircle setRadius")
            return super.radius
        }
    }
    override var diameter: Int {
        set{
            print("SubSircle setDiameter")
            super.diameter = newValue > 0 ? newValue : 0
            
        }
        get{
            print("SubSircle getDiameter")
            return super.diameter
        }
    }
    
}
var circle = SubSircle()

circle.radius = 9
print("=======")
print(circle.diameter)
print("=======")
circle.diameter = 20
print("=======")
print(circle.radius)

【打印結(jié)果】

SubSircle setRadius
=======
SubSircle getDiameter
Circle getDiameter
SubSircle setRadius
18
=======
SubSircle setDiameter
Circle setDiameter
SubSircle setRadius
=======
SubSircle setRadius
10


1.2 重寫類型屬性

  • class修飾的計(jì)算類型屬性白翻,可以被子類重寫(存儲類型屬性不可以被重寫)
  • static修飾的類型屬性(存儲、計(jì)算)绢片,不可以被子類重寫

2. 屬性觀察器

  • 可以在子類中為父類屬性(除了只讀計(jì)算屬性滤馍、let屬性)增加屬性觀察器
  • 父類的屬性在他自己的初始化器中賦值不會觸發(fā)屬性觀察器岛琼,但是在子類的初始化器中賦值會觸發(fā)屬性觀察器

3. 初始化器

  • 類、結(jié)構(gòu)體巢株、枚舉都可以定義初始化器
  • 類有兩種初始化器:指定初始化器槐瑞、便捷初始化器
  • 每一個類至少要有一個指定初始化器,指定初始化器是類的主要初始化器
  • 默認(rèn)初始化器總是類的指定初始化器
//指定初始化
class Person {
    var name: String = ""
    var age: Int = 0
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

//便捷初始化
class Student {
    var name: String = ""
    var age: Int = 0
     convenience init(name: String, age: Int){
          self.init()
          self.name = name
          self.age = age
      }
}
var p = Person(name: "Jack", age: 18)
var s = Student()
var s2 = Student(name: "Jack", age: 18)

注意: 如果重新寫了指定初始化器纯续。則init()不再自動生成


3.1 初始化器的相互調(diào)用規(guī)則
  • 指定初始化器必須從他的直系父類調(diào)用指定初始化器
  • 便捷初始化器必須從相同的類里調(diào)用另一個初始化器
  • 便捷初始化器最終必須調(diào)用一個指定初始化器
3.2 兩段式初始化

??Swift在變成方面為了保證初始化過程中的安全随珠,設(shè)定了兩段式初始化安全檢查猬错。

第一階段:初始化所有存儲屬性

  • 外層調(diào)用指定、便捷初始化器
  • 分配內(nèi)存給實(shí)例茸歧,但未初始化
  • 指定初始化器確保當(dāng)前類定義的存儲屬性都初始化
  • 指定初始化器調(diào)用父類的初始化器倦炒,不斷向上調(diào)用,形成初始化器鏈

第二階段:設(shè)置新的存儲屬性

  • 從頂部初始化器往下软瞎,鏈中的每一個指定初始化器都有機(jī)會進(jìn)一步制定實(shí)例
  • 從初始化器現(xiàn)在能夠使用self(訪問逢唤、修改它的屬性,調(diào)用它的實(shí)例方法等等)
  • 最終涤浇,鏈中任何便捷初始化器都有機(jī)會定制實(shí)例以及使用self
3.3 安全檢查
  • 指定初始化器必須保證在調(diào)用父類初始化器之前鳖藕,其所在類定義的所有存儲屬性都要初始化完成
  • 指定初始化器必須先調(diào)用父類初始化器,然后才能為集成的屬性設(shè)置新值
  • 便捷初始化器必須先調(diào)用同類中的其他初始化器只锭,然后再為任意屬性設(shè)置新值
  • 初始化器在第1階段初始化完成之前著恩,不能調(diào)用任何實(shí)例方法、不能讀取任何實(shí)例屬性的值蜻展,也不能引用self
  • 知道第一階段結(jié)束喉誊,實(shí)例才算完全合法
3.4 初始化器的重寫
  • 當(dāng)重寫父類的指定初始化器時,必須加上 override (即使子類的實(shí)現(xiàn)是便捷式初始化器)
  • 如果子類寫了一個匹配父類便捷初始化器的初始化器纵顾,不用加上override
  • 因?yàn)楦割惖谋憬莩跏蓟饔肋h(yuǎn)不會通過子類直接調(diào)用伍茄,因此,嚴(yán)格來說施逾,子類無法重寫父類的便捷初始化器

3.3 自動繼承
  • 1 如果子類沒有定義任何指定初始化器敷矫,他們會自動繼承父類所有的指定初始化器
  • 2 如果子類提供了父類所有指定初始化器的實(shí)現(xiàn)(要么通過方式1繼承,要么重寫)汉额,子類會自動繼承所有的父類便捷初始化器
  • 3 就算子類添加了更多的便捷初始化器曹仗,這些規(guī)則仍然適用
  • 4 子類以便捷初始化器的形式重寫父類的指定初始化器,也可以作為滿足規(guī)則②的一部分

4. required關(guān)鍵字

  • required關(guān)鍵字修飾指定初始化器闷愤,表明其所有子類都必須實(shí)現(xiàn)該初始化器(通過繼承或者重寫實(shí)現(xiàn))
  • 如果子類重寫了required初始化器時整葡,也必須加上required,不用加override
class Person {
    required init(){
        
    }
    init(age: Int) {
        
    }
}

class Student: Person {
    required init() {
        super.init()
    }
   
}

4. 可失敗初始化器

  • 類讥脐、結(jié)構(gòu)體遭居、枚舉都可以使用init啼器?定義可失敗初始化器
  • 不允許同時定義參數(shù)標(biāo)簽、參數(shù)個數(shù)俱萍、參數(shù)類型相同的可失敗初始化器和非可失敗初始化器
  • 可以用init端壳!定義隱式解包的可失敗初始化器
  • 可失敗初始化器可以調(diào)用非可失敗初始化器,非可失敗初始化器調(diào)用可失敗初始化器需要進(jìn)行解包
  • 如果初始化器調(diào)用了一個可失敗初始化器枪蘑,導(dǎo)致初始化失敗损谦,那么整個初始化過程都失敗,并且之后的代碼都停止執(zhí)行
  • 可以用一個非可失敗初始化器重寫一個可失敗初始化器岳颇,但反過來是不行的
//非可失敗 調(diào)用 可失敗初始化器
class Person {
   var name: String
   var age: Int
   init?(name:String) {
       if name.isEmpty {
           return nil
       }else{
           self.name = name
       }
       self.age = 18
   }
   
   convenience init() {
       self.init(name:"Jack")!//
   }
}
var p = Person()
print(p)



//可失敗 調(diào)用 非可失敗初始化器
class Person {
   var name: String
   var age: Int
  convenience init?(name:String) {
       self.init()
       if name.isEmpty {
           return nil
       }
   }
   
    init() {
       self.name = "jack"
       self.age = 10
   }
}


var p = Person(name: "")
print(p)
var p2 = Person(name: "Jack")
print(p2)

5. 反初始化器

deinit叫做反初始化器照捡,類似于C++的析構(gòu)函數(shù)、OC中的dealloc

  • 當(dāng)類的實(shí)例隊(duì)形被釋放內(nèi)存時话侧,就會調(diào)用實(shí)例隊(duì)形的deinit方法
  • deinit不接受任何參數(shù)栗精,不能寫小括號,不能自行調(diào)用
  • 父類的deinit能被子類繼承
  • 子類的deinit實(shí)現(xiàn)執(zhí)行完畢后會調(diào)用父類的deinit
class Animal {
    deinit {
        print("Animal deinit")
    }
}

class Dog:Animal {
    deinit {
        print("Dog deInit")
    }
}

var dog:Dog? = Dog()
dog = nil

【打印結(jié)果】:

Dog deInit
Animal deinit

6. 可選鏈

class Car { var price = 100000 }
class Dog { var weight = 0 }

class Person {
    var name: String = ""
    var dog: Dog = Dog()
    var car: Car? = Car()
    func age() -> Int {
       return 18
    }
    func eat() {
        print("Person eat")
    }
    subscript(index: Int) -> Int{
        return index
    }
    
}
var person:Person? = Person()

var age1 = person!.age()// Int
var age2 = person?.age()// Int?
var index = person?[6]//Int?

if let age = person?.age(){
    print(age)
}else{
    print("age() 調(diào)用失敗")
}
  • 如果可選項(xiàng)為nil瞻鹏,調(diào)用方法悲立、下標(biāo)、屬性失敗新博,結(jié)果為nil
  • 如果可選項(xiàng)不為nil薪夕,調(diào)用方法、下標(biāo)赫悄、屬性成功原献,結(jié)果會被包裝成可選項(xiàng)
    如果結(jié)果本身就是可選項(xiàng),則不會再次包裝
  • 多個涩蜘?可以連在一起嚼贡,如果鏈中的任何一個節(jié)點(diǎn)為nil,那么整個鏈就會調(diào)用失敗
func getName() -> String {
    return "Jack"
}
person?.name = getName()

注意: 如果person為nil同诫,則不會調(diào)用getName()

ar num1: Int? = 5
num1? = 10//Optional(10)
var num2: Int? = nil
num2? = 10//nil

print(num1,num2)
var dict:[String:(Int, Int) -> Int] = [
    "sum" : (+),
    "diff":(-)
]
var result = dict["sum"]?(10,20)//Optional(30)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粤策,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子误窖,更是在濱河造成了極大的恐慌叮盘,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霹俺,死亡現(xiàn)場離奇詭異柔吼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丙唧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門愈魏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事培漏∠澹” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵牌柄,是天一觀的道長畸悬。 經(jīng)常有香客問我,道長珊佣,這世上最難降的妖魔是什么蹋宦? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮咒锻,結(jié)果婚禮上冷冗,老公的妹妹穿的比我還像新娘。我一直安慰自己虫碉,他們只是感情好贾惦,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著敦捧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碰镜。 梳的紋絲不亂的頭發(fā)上兢卵,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機(jī)與錄音绪颖,去河邊找鬼秽荤。 笑死,一個胖子當(dāng)著我的面吹牛柠横,可吹牛的內(nèi)容都是我干的窃款。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼牍氛,長吁一口氣:“原來是場噩夢啊……” “哼晨继!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起搬俊,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤紊扬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后唉擂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體餐屎,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年玩祟,在試婚紗的時候發(fā)現(xiàn)自己被綠了腹缩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖藏鹊,靈堂內(nèi)的尸體忽然破棺而出润讥,到底是詐尸還是另有隱情,我是刑警寧澤伙判,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布象对,位于F島的核電站,受9級特大地震影響宴抚,放射性物質(zhì)發(fā)生泄漏勒魔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一菇曲、第九天 我趴在偏房一處隱蔽的房頂上張望冠绢。 院中可真熱鬧,春花似錦常潮、人聲如沸弟胀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孵户。三九已至,卻和暖如春岔留,著一層夾襖步出監(jiān)牢的瞬間夏哭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工献联, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留竖配,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓里逆,卻偏偏與公主長得像进胯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子原押,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348