日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

22.协议

發(fā)布時(shí)間:2025/3/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 22.协议 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  協(xié)議定義了一個(gè)藍(lán)圖,規(guī)定了用來實(shí)現(xiàn)某一特定任務(wù)或者功能的方法、屬性,以及其他需要的東西。類、結(jié)構(gòu)體或枚舉都可以采納協(xié)議,并為協(xié)議定義的這些要求提供具體實(shí)現(xiàn)。某個(gè)類型能夠滿足某個(gè)協(xié)議的要求,就可以說該類型“符合”這個(gè)協(xié)議。

  除了采納協(xié)議的類型必須實(shí)現(xiàn)的要求外,還可以對協(xié)議進(jìn)行擴(kuò)展,通過擴(kuò)展來實(shí)現(xiàn)一部分要求或者實(shí)現(xiàn)一些附加功能,這樣采納協(xié)議的類型就能夠使用這些功能。

1.協(xié)議語法

//協(xié)議語法 protocol SomeProtocol {// 這里是協(xié)議的定義部分 }//類型實(shí)現(xiàn)協(xié)議:類型名稱后加上協(xié)議名稱,中間以冒號(:)分隔。采納多個(gè)協(xié)議時(shí),各協(xié)議之間用逗號(,)分隔 struct SomeStructure: FirstProtocol, AnotherProtocol {// 這里是結(jié)構(gòu)體的定義部分 }//擁有父類的類型實(shí)現(xiàn)協(xié)議:將父類名放在協(xié)議名之前,以逗號分隔 class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {// 這里是類的定義部分 }

2.屬性要求

  • 協(xié)議可以要求采納協(xié)議的類型提供特定名稱和類型的實(shí)例屬性或類型屬性。協(xié)議不指定屬性是存儲型屬性還是計(jì)算型屬性,它只指定屬性的名稱和類型。此外,協(xié)議還指定屬性是可讀的還是可讀可寫的。
  • 如果協(xié)議要求屬性是可讀可寫的,那么該屬性不能是常量屬性或只讀的計(jì)算型屬性。如果協(xié)議只要求屬性是可讀的,那么該屬性不僅可以是可讀的,如果代碼需要的話,還可以是可寫的。
//協(xié)議定義 protocol CompanyPersonProtocol {var name: String{ get };var age: Int{ get set };static var companyName: String{ get }; }//協(xié)議實(shí)現(xiàn) class Company: CompanyPersonProtocol {var name: String;var age: Int;static var companyName: String{return "LGF";};init(name: String, age: Int){self.name = name;self.age = age;} }//使用 var company = Company(name: "GofLee", age: 30); company.name = "LeeGof"; print("Name is \(company.name)"); //"Name is LeeGof\n"

3.方法要求

  • 協(xié)議可以要求采納協(xié)議的類型實(shí)現(xiàn)某些指定的實(shí)例方法或類方法。這些方法作為協(xié)議的一部分,像普通方法一樣放在協(xié)議的定義中,但是不需要大括號和方法體。可以在協(xié)議中定義具有可變參數(shù)的方法,和普通方法的定義方式相同。但是,不支持為協(xié)議中的方法的參數(shù)提供默認(rèn)值。
//協(xié)議定義 protocol RandomNumberGenerator {func random() -> Double; //實(shí)例方法static func description(); //類型方法 }//協(xié)議實(shí)現(xiàn) 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;}static func description(){print("Hello");} }//使用 let generator = LinearCongruentialGenerator(); print("Here's a random number: \(generator.random())"); //"Here's a random number: 0.37464991998171\n"

4.Mutating 方法要求

  • 有時(shí)需要在方法中改變方法所屬的實(shí)例。例如,在值類型(即結(jié)構(gòu)體和枚舉)的實(shí)例方法中,將 mutating 關(guān)鍵字作為方法的前綴,寫在 func 關(guān)鍵字之前,表示可以在該方法中修改它所屬的實(shí)例以及實(shí)例的任意屬性的值。
  • 特別注意:實(shí)現(xiàn)協(xié)議中的 mutating 方法時(shí),若是類類型,則不用寫 mutating 關(guān)鍵字。而對于結(jié)構(gòu)體和枚舉,則必須寫 mutating 關(guān)鍵字。?
//協(xié)議定義 protocol Togglable {mutating func toggle(); }//協(xié)議實(shí)現(xiàn) enum OnOffSwitch: Togglable {case Off, On;mutating func toggle(){switch self{case Off:self = On;case On:self = Off;}} }//使用 var lightSwitch = OnOffSwitch.Off lightSwitch.toggle(); print("lightSwitch: \(lightSwitch)"); //"lightSwitch: On\n"

5.構(gòu)造器要求

  • 在采納協(xié)議的類中實(shí)現(xiàn)構(gòu)造器,無論是指定構(gòu)造器還是便利構(gòu)造器,都必須為構(gòu)造器實(shí)現(xiàn)標(biāo)上?required?修飾符。
  • 和第三點(diǎn)類似,注意一個(gè)地方:如果類已經(jīng)被標(biāo)記為 final,那么不需要在協(xié)議構(gòu)造器的實(shí)現(xiàn)中使用 required 修飾符,因?yàn)?span id="ozvdkddzhkzd" class="s3"> final 類不能有子類。
protocol SomeProtocol {init(someParameter: Int); }class SomeClass: SomeProtocol {required init(someParameter: Int){// 這里是構(gòu)造器的實(shí)現(xiàn)部分 } }

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

  協(xié)議可以像其他普通類型一樣使用,使用場景如下:

  • 作為函數(shù)、方法或構(gòu)造器中的參數(shù)類型或返回值類型
  • 作為常量、變量或?qū)傩缘念愋?/span>
  • 作為數(shù)組、字典或其他容器中的元素類型
  • //協(xié)議定義 protocol RandomNumberGenerator {func random() -> Double; }//協(xié)議實(shí)現(xiàn) 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;} }class Dice {let sides: Int;let generator: RandomNumberGenerator; //協(xié)議作為屬性類型//協(xié)議作為方法參數(shù) init(sides: Int, generator: RandomNumberGenerator){self.sides = sides;self.generator = generator;}func roll() -> Int{return Int(generator.random() * Double(sides)) + 1;} }var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator());

    7.委托(代理)模式

    • 委托是一種設(shè)計(jì)模式,它允許類或結(jié)構(gòu)體將一些需要它們負(fù)責(zé)的功能委托給其他類型的實(shí)例。委托模式的實(shí)現(xiàn)很簡單:定義協(xié)議來封裝那些需要被委托的功能,這樣就能確保采納協(xié)議的類型能提供這些功能。委托模式可以用來響應(yīng)特定的動(dòng)作,或者接收外部數(shù)據(jù)源提供的數(shù)據(jù),而無需關(guān)心外部數(shù)據(jù)源的類型。
    //委托定義 protocol WebServiceProtocol {func requestSuccess(data: String);func requestFailed(error: String); }//委托實(shí)現(xiàn) class LoginViewController: WebServiceProtocol {func requestSuccess(data: String){print("調(diào)用結(jié)果:\(data)");}func requestFailed(error: String){print("\(error)");} }class WebServiceRequest {var delegate: WebServiceProtocol;init(delegate: WebServiceProtocol){self.delegate = delegate;}func userLogin(userName: String, password: String){delegate.requestSuccess("調(diào)用成功");} }var loginVC = LoginViewController(); var webService = WebServiceRequest(delegate: loginVC); webService.userLogin("aa", password: "bb");

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

    • 即便無法修改源代碼,依然可以通過擴(kuò)展令已有類型采納并符合協(xié)議。通過擴(kuò)展令已有類型采納并符合協(xié)議時(shí),該類型的所有實(shí)例也會(huì)隨之獲得協(xié)議中定義的各項(xiàng)功能。
    • 這個(gè)在項(xiàng)目開發(fā)中比較常用,例如我們可以把UITableView的委托放在擴(kuò)展中去實(shí)現(xiàn),這樣能更好的分離代碼。

    9.通過擴(kuò)展采納協(xié)議

    • 當(dāng)一個(gè)類型已經(jīng)符合了某個(gè)協(xié)議中的所有要求,卻還沒有聲明采納該協(xié)議時(shí),可以通過空擴(kuò)展體的擴(kuò)展來采納該協(xié)議
    • 釋義:即使?jié)M足了協(xié)議的所有要求,類型也不會(huì)自動(dòng)采納協(xié)議,必須顯式地采納協(xié)議。
    protocol TextRepresentable {var textualDescription: String { get }; }struct Hamster {var name: String;var textualDescription: String{return "A hamster named \(name)";} }//必須顯示的采納協(xié)議 extension Hamster: TextRepresentable {}let simonTheHamster = Hamster(name: "Simon"); let somethingTextRepresentable: TextRepresentable = simonTheHamster; print(somethingTextRepresentable.textualDescription); //"A hamster named Simon\n"

    10.協(xié)議類型的集合

    協(xié)議類型可以在數(shù)組或者字典這樣的集合中使用。

    let things: [TextRepresentable] = [game, d12, simonTheHamster]; //數(shù)組中的變量都是實(shí)現(xiàn)了TextRepresentable的類型

    11.協(xié)議的繼承

    • 協(xié)議能夠繼承一個(gè)或多個(gè)其他協(xié)議,可以在繼承的協(xié)議的基礎(chǔ)上增加新的要求。協(xié)議的繼承語法與類的繼承相似,多個(gè)被繼承的協(xié)議間用逗號分隔。
    //釋義:任何采納 InheritingProtocol 協(xié)議的類型在滿足該協(xié)議的要求時(shí),也必須滿足 SomeProtocol、AnotherProtocol 協(xié)議的要求。 //偽代碼 protocol InheritingProtocol: SomeProtocol, AnotherProtocol {// 這里是協(xié)議的定義部分 }

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

    • 可以在協(xié)議的繼承列表中,通過添加 class 關(guān)鍵字來限制協(xié)議只能被類類型采納,而結(jié)構(gòu)體或枚舉不能采納該協(xié)議。class 關(guān)鍵字必須第一個(gè)出現(xiàn)在協(xié)議的繼承列表中,在其他繼承的協(xié)議之前。
    //偽代碼protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {// 這里是類類型專屬協(xié)議的定義部分}

    13.協(xié)議合成

    • 有時(shí)候需要同時(shí)采納多個(gè)協(xié)議,你可以將多個(gè)協(xié)議采用 protocol<SomeProtocol, AnotherProtocol> 這樣的格式進(jìn)行組合,稱為 協(xié)議合成(protocol composition)。你可以在 <> 中羅列任意多個(gè)你想要采納的協(xié)議,以逗號分隔。
    • 協(xié)議合成并不會(huì)生成新的、永久的協(xié)議類型,而是將多個(gè)協(xié)議中的要求合成到一個(gè)只在局部作用域有效的臨時(shí)協(xié)議中。?
    //協(xié)議定義 protocol Named {var name: String { get };}protocol Aged {var age: Int { get };}struct Person: Named, Aged {var name: String;var age: Int; }//協(xié)議合成作為方法參數(shù) func wishHappyBirthday(celebrator: protocol<Named, Aged>) {print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!"); }let person = Person(name: "Gof", age: 30); wishHappyBirthday(person);

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

      使用類型轉(zhuǎn)換中描述的 is as 操作符來檢查協(xié)議一致性,即是否符合某協(xié)議,并且可以轉(zhuǎn)換到指定的協(xié)議類型。檢查和轉(zhuǎn)換到某個(gè)協(xié)議類型在語法上和類型的檢查和轉(zhuǎn)換完全相同:

  • is 用來檢查實(shí)例是否符合某個(gè)協(xié)議,若符合則返回 true,否則返回 false
  • as? 返回一個(gè)可選值,當(dāng)實(shí)例符合某個(gè)協(xié)議時(shí),返回類型為協(xié)議類型的可選值,否則返回 nil
  • as! 將實(shí)例強(qiáng)制向下轉(zhuǎn)換到某個(gè)協(xié)議類型,如果強(qiáng)轉(zhuǎn)失敗,會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤。
  • protocol HasArea {var area: Double { get }; }class Country: HasArea {var area: Double;init(area: Double){self.area = area;} }class Animal {var legs: Int;init(legs: Int){self.legs = legs;} }let country = Country(area: 243_610); let animal = Animal(legs: 4);country is HasArea; //true country as? HasArea; //Country animal as? HasArea; //nil //animal as! HasArea; //錯(cuò)誤

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

    • 在協(xié)議中使用 optional 關(guān)鍵字作為前綴來定義可選要求。使用可選要求時(shí)(例如,可選的方法或者屬性),它們的類型會(huì)自動(dòng)變成可選的。比如,一個(gè)類型為 (Int) -> String 的方法會(huì)變成 ((Int) -> String)?
    • 協(xié)議中的可選要求可通過可選鏈?zhǔn)秸{(diào)用來使用,因?yàn)椴杉{協(xié)議的類型可能沒有實(shí)現(xiàn)這些可選要求。

    ?【特別注意】:

  • 可選的協(xié)議要求只能用在標(biāo)記 @objc 特性的協(xié)議中。該特性表示協(xié)議將暴露給 Objective-C 代碼,即使你不打算和 Objective-C 有什么交互,如果你想要指定可選的協(xié)議要求,那么還是要為協(xié)議加上 @objc 特性。
  • 標(biāo)記 @objc 特性的協(xié)議只能被繼承自 Objective-C 類的類或者 @objc 類采納,其他類以及結(jié)構(gòu)體和枚舉均不能采納這種協(xié)議。
  • import Foundation@objc protocol CounterDataSource {optional var fixedIncrement: Int { get };optional func incrementForCount(count: Int) -> Int; }//這里注意ThreeSource繼承自NSObject類,如果不繼承自NSObject類,會(huì)怎樣提示呢? class ThreeSource: NSObject, CounterDataSource {let fixedIncrement = 3; }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(); counter.dataSource = ThreeSource(); counter.increment(); print(counter.count);

    16.協(xié)議擴(kuò)展

    • 協(xié)議可以通過擴(kuò)展來為采納協(xié)議的類型提供屬性、方法以及下標(biāo)的實(shí)現(xiàn)。通過這種方式,你可以基于協(xié)議本身來實(shí)現(xiàn)這些功能,而無需在每個(gè)采納協(xié)議的類型中都重復(fù)同樣的實(shí)現(xiàn),也無需使用全局函數(shù)。
    protocol RandomNumberGenerator {func random() -> Double; }extension RandomNumberGenerator {func randomBool() -> Bool{return random() > 0.5;} }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(); print("Here's a random number: \(generator.random())"); print("And here's a random Boolean: \(generator.randomBool())");

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/LeeGof/p/5682784.html

    總結(jié)

    以上是生活随笔為你收集整理的22.协议的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。