iOS開發(fā) - 「Swift 學(xué)習(xí)」Swift協(xié)議

Swift協(xié)議

協(xié)議規(guī)定了用來實(shí)現(xiàn)某一特定功能所必需的方法屬性

類窜骄、結(jié)構(gòu)體、枚舉類型都可以遵循協(xié)議摆屯,并提供具體實(shí)現(xiàn)來完成協(xié)議定義的方法和功能邻遏。
能夠滿足協(xié)議要求的類型被稱為遵循此協(xié)議

(一)協(xié)議的聲明\color{red}{(協(xié)議本身是不實(shí)現(xiàn)任何功能的)}

協(xié)議的定義方式(關(guān)鍵詞:protocol):

protocol ProtocolName {
    // 協(xié)議內(nèi)容(聲明屬性/方法)
}

協(xié)議對屬性聲明的規(guī)定

協(xié)議用于指定特定的實(shí)例屬性或類屬性,而不用指定是存儲(chǔ)型還是計(jì)算型的屬性虐骑。必須要指明是只讀的還是可讀可寫的屬性准验。

通常用var關(guān)鍵詞聲名變量屬性,在類型聲明后面加{set get}表示是可讀可寫屬性廷没,用{get}表示只讀屬性

protocol firstProtocol {
    //聲明協(xié)議屬性(可讀可寫)
    var english:Float{set get}
    var chinese:Double{set get}
    var mathematics:Double{set get}
    //聲明協(xié)議方法
    func minResults() -> String
    func maxResults() -> String
}
//協(xié)議的繼承
protocol secondProtocol:firstProtocol{
     //聲明只讀型的協(xié)議屬性
    var ranking:String{get}
    var name:String{get}
}

//FirstClass類遵循secondProtocol協(xié)議糊饱,需要FirstClass類實(shí)現(xiàn)secondProtocol協(xié)議中的屬性及方法
class FirstClass:secondProtocol {
    //實(shí)現(xiàn)協(xié)議中的只讀屬性
    let ranking = "第三名"
    let name = "小明"
    
    var english:Float = 78.50
    
    var chinese = 88.0
    
    var mathematics = 95.0
    
    func minResults() -> String {
        return "小明本次成績數(shù)學(xué)是最高分95.0"
    }
    
    func maxResults() -> String {
        return "小明本次成績最低分是英語78.5"
    }
}

調(diào)用

let student = FirstClass()
print("\(student.maxResults())")

調(diào)用結(jié)果

小明本次成績最低分是英語78.5

協(xié)議對構(gòu)造器的聲明

協(xié)議是可以要求它的遵循者實(shí)現(xiàn)指定的構(gòu)造器
在協(xié)議的定義中\color{red}{只需要寫下構(gòu)造器的聲明部分},不需要花括號(hào)及構(gòu)造器的實(shí)體

*/
protocol ProtocolName {
   init(someParameter: Int)
}
*/

protocol tcpprotocol {
    init (aprot:Int)
}

協(xié)議中對Mutating方法的規(guī)定

若需要在方法中改變實(shí)例颠黎,例如另锋,值類型(結(jié)構(gòu)體,枚舉)的實(shí)例方法中狭归,將mutating關(guān)鍵字作為函數(shù)的前綴夭坪,寫在func之前,表示可以在該方法中修改它所屬的實(shí)例及其實(shí)例屬性的值过椎。

protocol daysofaweek {
    mutating func show()
}

enum days: daysofaweek {
    case sun, mon, tue, wed, thurs, fri, sat
    mutating func show() {
        switch self {
        case .sun:
            self = .sun
            print("Sunday")
        case .mon:
            self = .mon
            print("Monday")
        case .tue:
            self = .tue
            print("Tuesday")
        case .wed:
            self = .wed
            print("Wednesday")
        case .thurs:
            self = .thurs
            print("Wednesday")
        case .fri:
            self = .fri
            print("Firday")
        case .sat:
            self = .sat
            print("Saturday")
        default:
            print("NO Such Day")
        }
    }
}

調(diào)用

var res = days.wed
res.show()

調(diào)用結(jié)果

Wednesday

(二)協(xié)議的實(shí)現(xiàn)

協(xié)議構(gòu)造器在類中的實(shí)現(xiàn)

在遵循該協(xié)議的類中實(shí)現(xiàn)構(gòu)造器室梅,并指定其為類的指定構(gòu)造器或便利構(gòu)造器,必須給\color{red}{構(gòu)造器的實(shí)現(xiàn)}"required"修飾

//協(xié)議構(gòu)造器的實(shí)現(xiàn)
class SomeClass: ProtocolName {
   required init(someParameter: Int) {
      // 構(gòu)造器實(shí)現(xiàn)
   }
}
protocol tcpprotocol {
    init (aprot:Int)
}

class tcpClass:tcpprotocol {
    required init(aprot: Int) {
        print("實(shí)現(xiàn)指定構(gòu)造器方法")
    }
}

class TestMainClass {
    var num:Int//局部變量
    init(aprot:Int){
        self.num = aprot
    }
}

class TestSubClass:TestMainClass,tcpprotocol {
    var num2:Int
    init(num1:Int,num2:Int){
        self.num2 = num2
        super.init(aprot: num1)
    }
    //遵循協(xié)議疚宇,加上"required" 繼承父類重寫父類構(gòu)造器加上"override"
    required override  convenience init(aprot: Int) {
        self.init(num1: aprot, num2: 10)
    }
}

調(diào)用

let tcp = tcpClass(aprot: 3)
print("實(shí)現(xiàn)協(xié)議方法:\(tcp)")

調(diào)用結(jié)果

實(shí)現(xiàn)指定構(gòu)造器方法
實(shí)現(xiàn)協(xié)議方法:Swift_study.tcpClass

協(xié)議類型

\color{red}{協(xié)議本身是不實(shí)現(xiàn)任何功能的}亡鼠,但是協(xié)議可以被當(dāng)做類型使用
\color{red}{???????????????????????????????????????}
\color{BlueViolet}{協(xié)議類型的使用場景:}
\color{red}{?} \color{BlueViolet}{作為函數(shù)、方法或構(gòu)造器中的參數(shù)類型或返回值類型}
\color{red}{?} \color{BlueViolet}{作為常量敷待、變量或?qū)傩缘念愋蛚
\color{red}{?} \color{BlueViolet}{作為數(shù)組间涵、字典或其他容器中的元素類型}
\color{red}{???????????????????????????????????????}

protocol TestProtocolA{
    var num:Int{get set}
    func calc(sum:Int)
}

protocol ResultProtocol{
//將協(xié)議TestProtocolA作為定義方法時(shí)的參數(shù)類型
    func print(target: TestProtocolA)
}

class XiaoHong:ResultProtocol{
    func print(target: TestProtocolA) {
        target.calc(sum: 1)
    }
}

class XiaoQiang:ResultProtocol {
    func print(target: TestProtocolA) {
        target.calc(sum: 5)
    }
}

class DaMing:TestProtocolA {
    var num: Int = 10
    
    func calc(sum: Int) {
        num -= sum
        print("大明嘗試\(sum)次通過")
    
        if num <= 0{
            print("大明缺席考試")
        }
    }
}

class Player {
    var stmark:ResultProtocol!
    
    init(stmark:ResultProtocol){
        self.stmark = stmark
    }
    
    func print(target:TestProtocolA){
        stmark.print(target: target)
    }
}

調(diào)用

let marks = Player(stmark: XiaoHong())
let marksec = DaMing()
marks.print(target: marksec)
        
marks.stmark = XiaoQiang()
marks.print(target: marksec)
marks.print(target: marksec)
marks.print(target: marksec)

調(diào)用結(jié)果

大明嘗試1次通過
大明嘗試5次通過
大明嘗試5次通過
大明缺席考試
大明嘗試5次通過
大明缺席考試

在擴(kuò)展中添加遵循的協(xié)議

擴(kuò)展可以為已存在的類型添加\color{DarkOrange}{屬性、方法榜揖、下標(biāo)腳本浑厚、} \color{red}{協(xié)議}等成員

//在擴(kuò)展中添加協(xié)議成員
enum ageType
{
    case Baby,Child,Teenager,Young,Elderly,Normal
}

protocol AgeClasificationProtocol {
    var age: Int { get }
    func agecClassified() -> ageType
}

//創(chuàng)建Actor類
class Actor {

    let firstname:String
    let lastname:String
    //很神奇股耽,對Actor擴(kuò)展時(shí)增加了AgeClasificationProtocol協(xié)議根盒,在此實(shí)現(xiàn)協(xié)議里的屬性钳幅、方法也是可以的(也可以在擴(kuò)展中實(shí)現(xiàn))
    var age:Int
    init(firstname:String,lastname:String) {
        self.firstname = firstname;
        self.lastname = lastname;
        self.age = 13
    }
}

//對Actor類擴(kuò)展時(shí)添加AgeClasificationProtocol協(xié)議
extension Actor:AgeClasificationProtocol{
    
    func fullname() -> String {
        var name: String
        name = firstname + " " + lastname
        return name
    }
    
    //實(shí)現(xiàn)協(xié)議方法
    func agecClassified() -> ageType {
        switch age{
        case 0...2:
            return .Baby
        case 3...12:
            return .Child
        case 13...19:
            return .Teenager
        case 20...40:
            return .Young
        case let x where x > 65:
            return .Elderly
        default:
            return .Normal
        }
    }
    
    // () -> ageType 函數(shù)類型的參數(shù)
    func ageTypeName(typeFunc:() -> ageType) -> String {
        let type = typeFunc()
        
        switch type {
        case .Baby:
            return "嬰兒"
        case .Child:
            return "小孩兒"
        case .Teenager:
            return "少年"
        case .Young:
            return "青年"
        case .Elderly:
            return "長者"
        default:
            return "未知"
        }
    }
}

調(diào)用

let xiaoming = Actor(firstname: "王", lastname: "小明")
xiaoming.age = 12
let ageName = xiaoming.ageTypeName(typeFunc: xiaoming.agecClassified)
print("演員的全名:\(xiaoming.fullname())")
print("\(xiaoming.fullname()):所屬的年齡段:\(ageName)")

調(diào)用結(jié)果

演員的全名:王 小明
王 小明:所屬的年齡段:小孩兒

協(xié)議的繼承

協(xié)議是能夠繼承\color{red}{一個(gè)或者多個(gè)}其他協(xié)議,可以在繼承的協(xié)議基礎(chǔ)上增加新的內(nèi)容要求炎滞。
語法:協(xié)議的繼承語法與類的繼承相似敢艰,\color{red}{多個(gè)被繼承的協(xié)議之間用逗號(hào)隔開}

//protocol 新的協(xié)議名: 被繼承的協(xié)議, 被繼承的協(xié)議,其他被繼承的協(xié)議 { // 增加的新的協(xié)議定義}
protocol NewProtocolName: SomeInheritingProtocol, AnotherInheritingProtocol {
    // 增加的新的協(xié)議定義
}

protocol firstProtocol {
    
    var english:Float{set get}
    var chinese:Double{set get}
    var mathematics:Double{set get}
    
    func minResults() -> String
    func maxResults() -> String
}

protocol secondProtocol:firstProtocol{
    
    var ranking:String{get}
    var name:String{get}
}


class FirstClass:secondProtocol {
    
    let ranking = "第三名"
    
    let name = "小明"
    
    var english:Float = 78.50
    
    var chinese = 88.0
    
    var mathematics = 95.0
    
    func minResults() -> String {
        return "小明本次成績數(shù)學(xué)是最高分95.0"
    }
    
    func maxResults() -> String {
        return "小明本次成績最低分是英語78.5"
    }
}

調(diào)用

let student = FirstClass()
print("\(student.maxResults())")

調(diào)用結(jié)果

小明本次成績最低分是英語78.5

定義類的專屬協(xié)議

可以在協(xié)議的繼承列表中,通過\color{red}{添加class關(guān)鍵字册赛,限制協(xié)議只能適配到類(Class)類型}钠导。

注意:class關(guān)鍵字必須是\color{red}{第一個(gè)出現(xiàn)在協(xié)議的繼承列表中},其后森瘪,才是其他繼承協(xié)議牡属。

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// 協(xié)議的定義內(nèi)容
}

protocol TcpProtocol {
    init(num:Int)
}
//用class修飾符在協(xié)議的繼承列表中定義類的專屬協(xié)議ExclusiveProtocol
protocol ExclusiveProtocol:class,TcpProtocol{
    init(num1:Int,num2:Int)
}
//TcpProtocol協(xié)議可以被結(jié)構(gòu)體遵循
struct School:TcpProtocol{
    init(num: Int) {
        print("市第\(num)中學(xué)")
    }
}
//ExclusiveProtocol協(xié)議已經(jīng)不能被結(jié)構(gòu)體類型遵循了
/*
struct Hospital:ExclusiveProtocol {
    init(num: Int) {
        print("市第\(num)醫(yī)院")
    }
}
*/

//Hospital類遵循專屬協(xié)議ExclusiveProtocol
class Hospital:ExclusiveProtocol{
    
    var area:Int
    var num:Int
    init(area: Int, num: Int) {
        self.area = area
        self.num = num
        print("\(area)區(qū)-\(num)號(hào)醫(yī)院")
    }

    required convenience init(num1: Int, num2: Int) {
        self.init(area: num1, num: num2)

    }

    required convenience init(num: Int) {
        self.init(area: 5, num: num)
    }
}


class CityHospital:Hospital{
    var address:String
    init(address:String,area:Int,num:Int){
        self.address = address
        super.init(area: area, num: num)
        
        print("\(address)-\(area)區(qū)-\(num)號(hào)醫(yī)院")
    }
    
    required convenience init(num1: Int, num2: Int) {
        self.init(address:"河北街",area: num1, num: num2)
    }
    
    required convenience init(num: Int) {
        self.init(address:"河?xùn)|街",area: num, num: 10)
    }
}

調(diào)用

let hospital = Hospital(num: 8);
let hospital_a = CityHospital(address: "河西街", area: 1, num: 2)
let hospital_b = CityHospital(num: 6)

調(diào)用結(jié)果

5區(qū)-8號(hào)醫(yī)院
1區(qū)-2號(hào)醫(yī)院
河西街-1區(qū)-2號(hào)醫(yī)院
6區(qū)-10號(hào)醫(yī)院
河?xùn)|街-6區(qū)-10號(hào)醫(yī)院

協(xié)議的合成

\color{red}{Swift支持合成多個(gè)協(xié)議},在需要同時(shí)遵循多個(gè)協(xié)議時(shí)很有用

protocol NameProtocol {
    var name:String{get}
}

protocol AgeProtocol {
    var age:Int{get}
}
//Worker遵循倆協(xié)議
struct Worker:NameProtocol,AgeProtocol {
    var name: String
    var age: Int
}

//NameProtocol & AgeProtocol合體
func showWorker(worker:NameProtocol & AgeProtocol){
    print("\(worker.name) is \(worker.age) years old")
}

調(diào)用

let zhangzong = Worker(name:"老張", age: 45)
print(zhangzong)
showWorker(worker: zhangzong)

調(diào)用結(jié)果

Worker(name: "老張", age: 45)
老張 is 45 years old

檢驗(yàn)協(xié)議的一致性

使用isas操作符檢查是否遵循某協(xié)議或強(qiáng)制轉(zhuǎn)化為某一協(xié)議類型

protocol HasArea {
    var area:Double{get}
}
//圓
class Circular:HasArea {
    let pi = 3.14159265
    var radius:Double
    var area: Double {
        return pi * radius * radius
    }
    init(radius:Double){
        self.radius = radius
    }
}


class Rectangular:HasArea {
    var width:Double
    var height:Double
    
    var area: Double{
        return width * height
    }
    
    init(width:Double,height:Double){
        self.width = width
        self.height = height
    }
}

class Hous{
    var rooms:Int = 0
    func configure(config: (Hous) -> Void) -> Hous {
        config(self)
        return self
    }
    
    func rooms(_ value: Int) -> Self {
        
        self.rooms = value
        return self
    }
}

調(diào)用

let hous = Hous().configure{ $0.rooms = 3 }
        print(hous.rooms)
        
        
        let objs:[AnyObject] = [Circular(radius: 2.4),
                                Rectangular(width: 5, height: 3),
                                Hous().rooms(3),
                                Hous().configure(config: {hous in
            hous.rooms = 5
        })]
        
        for obj in objs {
            if let objItem = obj as? HasArea{
                print("面積為:\(objItem.area)")
            }else {
                print("沒有面積概念")
            }
        }
        
        
        let pro = Hous().rooms(3)
        if pro is HasArea{
            //print("矩形的面積:\(pro.area)")
        }else {
            print("有\(zhòng)(pro.rooms)個(gè)房間")
        }

調(diào)用結(jié)果

3
面積為:18.095573664
面積為:15.0
沒有面積概念
沒有面積概念
有3個(gè)房間

\color{gray}{歡迎大佬兒來指正糾錯(cuò)扼睬,共同學(xué)習(xí)??4ぁ!}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末窗宇,一起剝皮案震驚了整個(gè)濱河市措伐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌军俊,老刑警劉巖侥加,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異粪躬,居然都是意外死亡担败,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門镰官,熙熙樓的掌柜王于貴愁眉苦臉地迎上來提前,“玉大人,你說我怎么就攤上這事朋魔♂校” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵警检,是天一觀的道長孙援。 經(jīng)常有香客問我,道長扇雕,這世上最難降的妖魔是什么拓售? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮镶奉,結(jié)果婚禮上础淤,老公的妹妹穿的比我還像新娘崭放。我一直安慰自己,他們只是感情好鸽凶,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布币砂。 她就那樣靜靜地躺著,像睡著了一般玻侥。 火紅的嫁衣襯著肌膚如雪决摧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天凑兰,我揣著相機(jī)與錄音掌桩,去河邊找鬼。 笑死姑食,一個(gè)胖子當(dāng)著我的面吹牛波岛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播音半,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼则拷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了祟剔?” 一聲冷哼從身側(cè)響起隔躲,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎物延,沒想到半個(gè)月后宣旱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叛薯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年浑吟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耗溜。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡组力,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抖拴,到底是詐尸還是另有隱情燎字,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布阿宅,位于F島的核電站候衍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏洒放。R本人自食惡果不足惜蛉鹿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望往湿。 院中可真熱鬧妖异,春花似錦惋戏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至矩乐,卻和暖如春龄句,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背散罕。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留傀蓉,地道東北人欧漱。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像葬燎,于是被迫代替她去往敵國和親误甚。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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