Swift協(xié)議
協(xié)議規(guī)定了用來實(shí)現(xiàn)某一特定功能所必需的
方法
和屬性
類窜骄、結(jié)構(gòu)體、枚舉
類型都可以遵循協(xié)議摆屯,并提供具體實(shí)現(xiàn)來完成協(xié)議定義的方法和功能邻遏。
能夠滿足協(xié)議要求的類型被稱為遵循此協(xié)議
(一)協(xié)議的聲明
協(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é)議的定義中,不需要花括號(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)造器,必須給用"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é)議類型
亡鼠,但是協(xié)議可以被當(dāng)做類型使用
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ò)展可以為已存在的類型添加 等成員
//在擴(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é)議是能夠繼承其他協(xié)議,可以在繼承的協(xié)議基礎(chǔ)上增加新的內(nèi)容要求炎滞。
語法:協(xié)議的繼承語法與類的繼承相似敢艰,
//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é)議的繼承列表中,通過钠导。
注意:class關(guān)鍵字必須是,其后森瘪,才是其他繼承協(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é)議的合成
,在需要同時(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é)議的一致性
使用is
和as
操作符檢查是否遵循某協(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è)房間