生活随笔
收集整理的這篇文章主要介紹了
22.协议
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
協議定義了一個藍圖,規定了用來實現某一特定任務或者功能的方法、屬性,以及其他需要的東西。類、結構體或枚舉都可以采納協議,并為協議定義的這些要求提供具體實現。某個類型能夠滿足某個協議的要求,就可以說該類型“符合”這個協議。
除了采納協議的類型必須實現的要求外,還可以對協議進行擴展,通過擴展來實現一部分要求或者實現一些附加功能,這樣采納協議的類型就能夠使用這些功能。
1.協議語法
//協議語法
protocol SomeProtocol {// 這里是協議的定義部分
}//類型實現協議:類型名稱后加上協議名稱,中間以冒號(:)分隔。采納多個協議時,各協議之間用逗號(,)分隔
struct SomeStructure: FirstProtocol, AnotherProtocol {// 這里是結構體的定義部分
}//擁有父類的類型實現協議:將父類名放在協議名之前,以逗號分隔
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {// 這里是類的定義部分
}
2.屬性要求
- 協議可以要求采納協議的類型提供特定名稱和類型的實例屬性或類型屬性。協議不指定屬性是存儲型屬性還是計算型屬性,它只指定屬性的名稱和類型。此外,協議還指定屬性是可讀的還是可讀可寫的。
- 如果協議要求屬性是可讀可寫的,那么該屬性不能是常量屬性或只讀的計算型屬性。如果協議只要求屬性是可讀的,那么該屬性不僅可以是可讀的,如果代碼需要的話,還可以是可寫的。
//協議定義
protocol CompanyPersonProtocol
{var name: String{ get };var age: Int{ get set };static var companyName: String{
get };
}//協議實現
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.方法要求
- 協議可以要求采納協議的類型實現某些指定的實例方法或類方法。這些方法作為協議的一部分,像普通方法一樣放在協議的定義中,但是不需要大括號和方法體。可以在協議中定義具有可變參數的方法,和普通方法的定義方式相同。但是,不支持為協議中的方法的參數提供默認值。
//協議定義
protocol RandomNumberGenerator
{func random() -> Double;
//實例方法static func description();
//類型方法
}//協議實現
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 方法要求
- 有時需要在方法中改變方法所屬的實例。例如,在值類型(即結構體和枚舉)的實例方法中,將 mutating 關鍵字作為方法的前綴,寫在 func 關鍵字之前,表示可以在該方法中修改它所屬的實例以及實例的任意屬性的值。
- 特別注意:實現協議中的 mutating 方法時,若是類類型,則不用寫 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 lightSwitch =
OnOffSwitch.Off
lightSwitch.toggle();
print("lightSwitch: \(lightSwitch)");
//"lightSwitch: On\n" 5.構造器要求
- 在采納協議的類中實現構造器,無論是指定構造器還是便利構造器,都必須為構造器實現標上?required?修飾符。
- 和第三點類似,注意一個地方:如果類已經被標記為 final,那么不需要在協議構造器的實現中使用 required 修飾符,因為 final 類不能有子類。
protocol SomeProtocol
{init(someParameter: Int);
}class SomeClass: SomeProtocol
{required init(someParameter: Int){// 這里是構造器的實現部分
}
} 6.協議作為類型
協議可以像其他普通類型一樣使用,使用場景如下:
作為函數、方法或構造器中的參數類型或返回值類型作為常量、變量或屬性的類型作為數組、字典或其他容器中的元素類型 //協議定義
protocol RandomNumberGenerator
{func random() ->
Double;
}//協議實現
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; //協議作為屬性類型//協議作為方法參數
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.委托(代理)模式
- 委托是一種設計模式,它允許類或結構體將一些需要它們負責的功能委托給其他類型的實例。委托模式的實現很簡單:定義協議來封裝那些需要被委托的功能,這樣就能確保采納協議的類型能提供這些功能。委托模式可以用來響應特定的動作,或者接收外部數據源提供的數據,而無需關心外部數據源的類型。
//委托定義
protocol WebServiceProtocol
{func requestSuccess(data: String);func requestFailed(error: String);
}//委托實現
class LoginViewController: WebServiceProtocol
{func requestSuccess(data: String){print("調用結果:\(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(
"調用成功");}
}var loginVC =
LoginViewController();
var webService = WebServiceRequest(
delegate: loginVC);
webService.userLogin("aa", password:
"bb");
8.通過擴展添加協議一致性
- 即便無法修改源代碼,依然可以通過擴展令已有類型采納并符合協議。通過擴展令已有類型采納并符合協議時,該類型的所有實例也會隨之獲得協議中定義的各項功能。
- 這個在項目開發中比較常用,例如我們可以把UITableView的委托放在擴展中去實現,這樣能更好的分離代碼。
9.通過擴展采納協議
- 當一個類型已經符合了某個協議中的所有要求,卻還沒有聲明采納該協議時,可以通過空擴展體的擴展來采納該協議
- 釋義:即使滿足了協議的所有要求,類型也不會自動采納協議,必須顯式地采納協議。
protocol TextRepresentable
{var textualDescription: String { get };
}struct Hamster
{var name: String;var textualDescription: String{return "A hamster named \(name)";}
}//必須顯示的采納協議
extension Hamster: TextRepresentable {}let simonTheHamster = Hamster(name:
"Simon");
let somethingTextRepresentable: TextRepresentable =
simonTheHamster;
print(somethingTextRepresentable.textualDescription); //"A hamster named Simon\n" 10.協議類型的集合
協議類型可以在數組或者字典這樣的集合中使用。
let things: [TextRepresentable] = [game, d12, simonTheHamster];
//數組中的變量都是實現了TextRepresentable的類型 11.協議的繼承
- 協議能夠繼承一個或多個其他協議,可以在繼承的協議的基礎上增加新的要求。協議的繼承語法與類的繼承相似,多個被繼承的協議間用逗號分隔。
//釋義:任何采納 InheritingProtocol 協議的類型在滿足該協議的要求時,也必須滿足 SomeProtocol、AnotherProtocol 協議的要求。
//偽代碼
protocol InheritingProtocol: SomeProtocol, AnotherProtocol
{// 這里是協議的定義部分
}
12.類類型專屬協議
- 可以在協議的繼承列表中,通過添加 class 關鍵字來限制協議只能被類類型采納,而結構體或枚舉不能采納該協議。class 關鍵字必須第一個出現在協議的繼承列表中,在其他繼承的協議之前。
//偽代碼protocol SomeClassOnlyProtocol:
class, SomeInheritedProtocol {// 這里是類類型專屬協議的定義部分}
13.協議合成
- 有時候需要同時采納多個協議,你可以將多個協議采用 protocol<SomeProtocol, AnotherProtocol> 這樣的格式進行組合,稱為 協議合成(protocol composition)。你可以在 <> 中羅列任意多個你想要采納的協議,以逗號分隔。
- 協議合成并不會生成新的、永久的協議類型,而是將多個協議中的要求合成到一個只在局部作用域有效的臨時協議中。?
//協議定義
protocol Named
{var name: String { get };}protocol Aged
{var age: Int { get };}struct Person: Named, Aged
{var name: String;var age: Int;
}//協議合成作為方法參數
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.檢查協議一致性
使用類型轉換中描述的 is 和 as 操作符來檢查協議一致性,即是否符合某協議,并且可以轉換到指定的協議類型。檢查和轉換到某個協議類型在語法上和類型的檢查和轉換完全相同:
is 用來檢查實例是否符合某個協議,若符合則返回 true,否則返回 false。as? 返回一個可選值,當實例符合某個協議時,返回類型為協議類型的可選值,否則返回 nil。as! 將實例強制向下轉換到某個協議類型,如果強轉失敗,會引發運行時錯誤。 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; //錯誤 15.可選的協議要求
- 在協議中使用 optional 關鍵字作為前綴來定義可選要求。使用可選要求時(例如,可選的方法或者屬性),它們的類型會自動變成可選的。比如,一個類型為 (Int) -> String 的方法會變成 ((Int) -> String)?。
- 協議中的可選要求可通過可選鏈式調用來使用,因為采納協議的類型可能沒有實現這些可選要求。
?【特別注意】:
可選的協議要求只能用在標記 @objc 特性的協議中。該特性表示協議將暴露給 Objective-C 代碼,即使你不打算和 Objective-C 有什么交互,如果你想要指定可選的協議要求,那么還是要為協議加上 @objc 特性。標記 @objc 特性的協議只能被繼承自 Objective-C 類的類或者 @objc 類采納,其他類以及結構體和枚舉均不能采納這種協議。 import Foundation@objc protocol CounterDataSource
{optional var fixedIncrement: Int { get };optional func incrementForCount(count: Int) ->
Int;
}//這里注意ThreeSource繼承自NSObject類,如果不繼承自NSObject類,會怎樣提示呢?
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.協議擴展
- 協議可以通過擴展來為采納協議的類型提供屬性、方法以及下標的實現。通過這種方式,你可以基于協議本身來實現這些功能,而無需在每個采納協議的類型中都重復同樣的實現,也無需使用全局函數。
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())");
?
轉載于:https://www.cnblogs.com/LeeGof/p/5682784.html
總結
以上是生活随笔為你收集整理的22.协议的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。