Swift學習之協(xié)議

協(xié)議

協(xié)議定義了用來實現(xiàn)某一特定任務或者功能的屬性胳岂、方法以及需要的東西。
類找御、結構體元镀、枚舉都可以采用協(xié)議,但是都必須實現(xiàn)協(xié)議所必須的要求霎桅。除了采納協(xié)議規(guī)定的要求栖疑,還可以給協(xié)議擴展一下方法、屬性滔驶,這樣采納該協(xié)議的類型就能夠使用這些功能遇革。

1.語法

protocol SomeProtocol1{
    //定義一下使用該協(xié)議要實現(xiàn)的內容
}
要讓自定義的類型采用協(xié)議,需要在需要的類型名后加上協(xié)議名揭糕,并用 “:” 隔開萝快,如果采納多個協(xié)議,協(xié)議之間用逗號隔開插佛。如果類型繼承某個類,需要將繼承的類寫在協(xié)議的最前面量窘。
class someClass:SomeSuperClass,SomeProtocol{

}

2.屬性要求

協(xié)議可以要求采納該協(xié)議的類型提供特定名稱和類型的實例屬性或者類型屬性雇寇。但協(xié)議不指定協(xié)議的屬性是存儲還是計算型屬性。它指定名字和類型蚌铜。此外,還可以指定屬性是可讀還是可寫的。
通常用var來指定屬性递胧,在類型聲明后加{set get}來表明屬性是可讀還是可寫的募寨。
protocol SomeProtocol2{
    var musetBeSettable:Int {set get} //如果有set,必須有get
    var doesnotBeSettable:Int {get}
}
在協(xié)議中定義類屬性的時候审葬,使用static 關鍵字修飾深滚,當類類型采納協(xié)議時,還可以用class 來聲明類型屬性
protocol FullName{
    var fullName:String{get}
}

struct Person:FullName {
    var fullName:String{ //提供FullName的屬性的get實現(xiàn)
        return "iyaqi"
    }
}
print(Person().fullName) // iyaqi

3.方法要求

協(xié)議可以要求采納該協(xié)議的類型必須實現(xiàn)指定的實例方法或者類方法涣觉,但是這些方法不需要提供具體的實現(xiàn)痴荐。類似屬性,可以類方法需用static關鍵字修飾官册,類類型還可以使用class修飾生兆。
protocol RandomNumberGenerator{
    func random()->Double
    //static func someMethod()
}
class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
    func random() -> Double {
        lastRandom = ((lastRandom * a + c) % m)
        return lastRandom / m
    }
}
let generator = LinearCongruentialGenerator()
generator.random() //0.3746499199817101
generator.random() //0.729023776863283
如果需要修改實例或者實例的屬性的值,需要在方法的func前面加 mutating膝宁。實現(xiàn)協(xié)議的 mutating方法時鸦难,如果是類類型根吁,在實現(xiàn)的方法前面不需要加 mutating,結構體合蔽、枚舉需要添加 mutating击敌。
protocol Togglable{
    mutating func toggle()
}
enum OnOffSwitch:Togglable{
    case Off,On
    mutating func toggle() {
        switch self{
        case .Off:
            self = .On
        case .On:
            self = .Off
        }
    }
}
var switcher = OnOffSwitch.Off
print("switcher's status:\(switcher)") //switcher's statu:Off\n
switcher.toggle()
print("switcher's status:\(switcher)") //switcher's statu:On\n

4.構造器要求

協(xié)議可以要求采納協(xié)議的類型實現(xiàn)指定的構造器。類似與普通的構造器一樣辈末,但是不需要具體實現(xiàn)愚争。
protocol aProtocol{
    init (someParameters:Int)
}
構造器在類中的實現(xiàn)
在類中的實現(xiàn),無需指定是指定構造器還是便利構造器,并且需要加上 required 修飾符
class someClass:aProtocol{
    init(a:Int){}
    required init(someParameters: Int) {
        //這里是實現(xiàn)部分挤聘。
    }
}

class superClass {
    init(someParameters:Int){}
}

class subClass: superClass,aProtocol {
    //父類和協(xié)議都定義了這個構造器轰枝,所以要加上 override & required
    override required init( someParameters: Int) {
        
        super.init(someParameters: 1)
    }
}

5.協(xié)議作為類型

//協(xié)議可以 像普通類型一樣,作為參數(shù)组去、返回值鞍陨,或者是屬性,數(shù)組从隆、字典中等容器的元素诚撵。
class Dice{
    let sides:Int
    let generator :LinearCongruentialGenerator //協(xié)議作為屬性
    init(sides:Int,generator:LinearCongruentialGenerator){ //協(xié)議作為參數(shù)
        self.sides = sides
        self.generator = generator
    }
    func roll()->Int{
        return Int(generator.random() * Double(sides)) + 1
    }
}


var dice = Dice(sides: 3, generator: LinearCongruentialGenerator())
for _ in 1...5{
    print(dice.roll()) //2,3,2,3,2
}

6.代理(委托)模式

委托是一種設計模式,它允許類和結構體將一些功能委托給其他類型的實例來操作键闺。委托的實現(xiàn)很簡單:定義協(xié)議封裝那些要實現(xiàn)的功能寿烟,這樣采納該協(xié)議的類型就能夠提供這些功能。
protocol DiceGame{
    var dice:Dice {get}
    func play()
}
protocol DiceGameDelegate{
    func diceDidStart(game:DiceGame)
    func game(game:DiceGame,didStartNewTurnWithDiceRoll dicRoll:Int)
    func gameEnd(game:DiceGame)
}

class SnakeAndLadders: DiceGame {
    let finalSquare = 25
    var dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
    var square = 0
    var board = [Int]()
    init(){
        board = [Int](count: finalSquare, repeatedValue: 0)
        board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
        board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
    }
    var delegate : DiceGameDelegate?
    func play() {
        square = 0
        delegate?.diceDidStart(self)
        gameLoop:while square != finalSquare{
            let diceRoll = dice.roll()
            delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
            switch square + diceRoll{
            case finalSquare:
                break gameLoop
            case let newSquare where newSquare > finalSquare:
                continue gameLoop
            default:
                square += diceRoll
                square += board[square]
            }
        }
        delegate?.gameEnd(self)
    }
}

7.通過擴展添加協(xié)議一致性

即便無法修改源代碼辛燥,依然可以用擴展令已有類型采納并符合協(xié)議筛武。協(xié)議可以為類型添加屬性、方法挎塌、下標等來讓類型符合協(xié)議的要求
protocol TextRepresentable{
    var textualDescription:String{get}
}
extension Dice:TextRepresentable{
    var textualDescription:String{
        return "a side of Dice"
    }
}
通過擴展來采納并實現(xiàn)協(xié)議徘六,跟在原始定義中實現(xiàn)是同樣的效果。

8.協(xié)議的集合

let things:[TextRepresentable] = [dice]
for thing in things{
    print(thing.textualDescription)
}

9.協(xié)議的繼承

協(xié)議能夠繼承一個或者多個協(xié)議榴都,多個協(xié)議之間用逗號隔開待锈,語法跟類的繼承相同。如果繼承的協(xié)議還繼承了其他協(xié)議嘴高,那么采納該協(xié)議的類型也必須實現(xiàn)其他協(xié)議的要求竿音。比如,協(xié)議B 繼承 協(xié)議A拴驮,類型C采納了B協(xié)議谍失,那么C必須也實現(xiàn)協(xié)議A規(guī)定的東西。

10.類類型專屬協(xié)議

可以在協(xié)議的繼承列表中莹汤,添加class 關鍵字表示該協(xié)議只能被類類型采納快鱼。其他類型不能采納。
protocol someProtocol4:class,TextRepresentable{
    //這里是類類型的定義部分
}

11.協(xié)議合成

如果采用多個協(xié)議,可以將多個協(xié)議放在protocol<>里面抹竹。表示采納的協(xié)議列表线罕,稱協(xié)議合成,協(xié)議之間用逗號隔開
protocol Named{
    var name:String{get}
}
protocol Aged{
    var age:Int {get set}
}
struct People :Named,Aged{
    var name:String
    var age:Int
}   
協(xié)議合成,這個方法的參數(shù)不關心類型窃判,之關心這個參數(shù)是否符合Named,Aged協(xié)議钞楼。
func wishHappyBirthday(celebrator:protocol<Named,Aged>){
    print("Happy birthday \(celebrator.name) for \(celebrator.age)")
}

let birthdayPerson = People(name: "iyaqi", age: 25)
print(wishHappyBirthday(birthdayPerson))

12.檢查協(xié)議一致性

使用is as來檢查協(xié)議一致性。即是否符合某協(xié)議袄琳,并且可以轉換到指定的協(xié)議類型
is 用來檢查實例是否符合某個協(xié)議询件,若符合則返回 true,否則返回 false唆樊。
as? 返回一個可選值宛琅,當實例符合某個協(xié)議時,返回類型為協(xié)議類型的可選值逗旁,否則返回 nil嘿辟。
as! 將實例強制向下轉換到某個協(xié)議類型,如果強轉失敗片效,會引發(fā)運行時錯誤红伦。

protocol HasArea{
    var area:Double{get}
}

class Circle: HasArea {
    let pi:Double = 3.1415
    var radius:Double
    init(radius:Double){
        self.radius = radius;
    }
    var area:Double{
        return radius * radius * pi
    }
}
class Country: HasArea {
    var area:Double
    init(area:Double){self.area = area}
}

class Animal {
    var legs:Int
    init(legs:Int){self.legs = legs}
}

var objects:[AnyObject] = [Circle(radius: 3),Country(area: 2000),Animal(legs: 2)]
for object in objects{
    if let hasAreaType = object as? HasArea{
        //在這里object會被轉化為 HasArea類型,雖然他們仍然是circle淀衣、country昙读、animal類型,當object 賦給 hasAreaType時膨桥,只能訪問area屬性
        print(hasAreaType.area) // 28.2735 ,200
    }
}

13.可選的協(xié)議要求

可以在協(xié)議中定義可以選擇實現(xiàn)的要求蛮浑,采納該協(xié)議的類型可以選擇是否采用這些要求。用optional關鍵字修飾国撵。注意陵吸,可選的協(xié)議要求只能用在標記@objc的協(xié)議中玻墅,標記@objc的協(xié)議只能被OC的類或者是@objc類采納介牙,其他類型均不能采納
@objc protocol CounterDataSource {
    optional func incrementForCount(count:Int)->Int
    optional var fixedIncrement:Int{get}
}

class Counter{
    var count = 0
    var datasource : CounterDataSource?
    func increment(){
        if let amount = datasource?.incrementForCount?(count){
            count += amount
        }else if let amount = datasource?.fixedIncrement{
            count += amount
        }
    }
}
var counter = Counter()

class threeSource: NSObject,CounterDataSource {
    let fixedIncrement = 3
}

counter.datasource = threeSource()
for _ in 1..<4{
    counter.increment() //
    print(counter.count) // 3 6 9
}

class  TowardsZeroSource:NSObject,CounterDataSource{
    func incrementForCount(count: Int) -> Int {
        if count == 0  {
            return 0
        }else if count < 0{
            return 1
        }else{
            return -1
        }
    }
}

print(counter.count) //9
counter.datasource = TowardsZeroSource()
counter.increment()
print(counter.count) //8

14.協(xié)議擴展

協(xié)議可以通過擴展來添加方法、屬性澳厢、下標等环础,基于此,可以通過給協(xié)議添加擴展剩拢,來實現(xiàn)這些功能线得,而無需在每個采納該協(xié)議的類型中添加這些功能。通過協(xié)議擴展徐伐,所有采納該協(xié)議的類型都會自動獲取到該擴展增加的方法實現(xiàn)贯钩,無需任何額外修改。
extension RandomNumberGenerator{
    func randomBool()->Bool{
        return random() > 0.5
    }
}

let generator2 = LinearCongruentialGenerator()
print(generator.random()) // 0.636466906721536
print(generator.randomBool()) // 0.636466906721536 > 0.5 返回 true
可以提供默認的實現(xiàn),也可以為協(xié)議添加限制條件
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市角雷,隨后出現(xiàn)的幾起案子祸穷,更是在濱河造成了極大的恐慌,老刑警劉巖勺三,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雷滚,死亡現(xiàn)場離奇詭異,居然都是意外死亡吗坚,警方通過查閱死者的電腦和手機祈远,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來商源,“玉大人车份,你說我怎么就攤上這事〈缎冢” “怎么了躬充?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長讨便。 經常有香客問我充甚,道長,這世上最難降的妖魔是什么霸褒? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任伴找,我火速辦了婚禮,結果婚禮上废菱,老公的妹妹穿的比我還像新娘技矮。我一直安慰自己,他們只是感情好殊轴,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布衰倦。 她就那樣靜靜地躺著,像睡著了一般旁理。 火紅的嫁衣襯著肌膚如雪樊零。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天孽文,我揣著相機與錄音驻襟,去河邊找鬼。 笑死芋哭,一個胖子當著我的面吹牛沉衣,可吹牛的內容都是我干的。 我是一名探鬼主播减牺,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼豌习,長吁一口氣:“原來是場噩夢啊……” “哼存谎!你這毒婦竟也來了?” 一聲冷哼從身側響起肥隆,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤愕贡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后巷屿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體固以,經...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年嘱巾,在試婚紗的時候發(fā)現(xiàn)自己被綠了憨琳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡旬昭,死狀恐怖篙螟,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情问拘,我是刑警寧澤遍略,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站骤坐,受9級特大地震影響绪杏,放射性物質發(fā)生泄漏。R本人自食惡果不足惜纽绍,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一蕾久、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拌夏,春花似錦僧著、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至站故,卻和暖如春皆怕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背世蔗。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工端逼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留朗兵,地道東北人污淋。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像余掖,于是被迫代替她去往敵國和親寸爆。 傳聞我的和親對象是個殘疾皇子礁鲁,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內容