Skip to main content

Swift协议

协议规定了用来实现某一特定功能所必需的方法和属性。

任意能够满足协议要求的类型被称为遵循(conform)这个协议。

类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。

语法

protocol SomeProtocol {
// 协议内容
}

要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号:分隔,作为类型定义的一部分。遵循多个协议时,各协议之间用逗号,分隔。

struct SomeStructure: FirstProtocol, AnotherProtocol {
// 结构体内容
}

如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔。

class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 类的内容
}

对属性的规定

协议用于指定特定的实例属性或类属性,而不用指定是存储型属性或计算型属性。此外还必须指明是只读的还是可读可写的。

协议中的通常用var来声明变量属性,在类型声明后加上{ set get }来表示属性是可读可写的,只读属性则用{ get }来表示。

protocol classa {

var marks: Int { get set }
var result: Bool { get }

func attendance() -> String
func markssecured() -> String

}

protocol classb: classa {

var present: Bool { get set }
var subject: String { get set }
var stname: String { get set }

}

class classc: classb {
var marks = 96
let result = true
var present = false
var subject = "Swift 协议"
var stname = "Protocols"

func attendance() -> String {
return "The \(stname) has secured 99% attendance"
}

func markssecured() -> String {
return "\(stname) has scored \(marks)"
}
}

let studdet = classc()
studdet.stname = "Swift"
studdet.marks = 98
studdet.markssecured()

对Mutating方法的规定

有时需要在方法中改变它的实例。

例如,值类型(结构体,枚举)的实例方法中,将mutating关键字作为函数的前缀,写在func之前,表示可以在该方法中修改它所属的实例及其实例属性的值。

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")
}
}
}

var res = days.wed
res.show()

对构造器的规定

protocol SomeProtocol {
init(someParameter: Int)
}

协议的继承

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// 协议定义
}

类专属的协议

你可以在协议的继承列表中,通过添加class关键字,限制协议只能适配到类(class)类型。

该class关键字必须是第一个出现在协议的继承列表中,其后,才是其他继承协议。

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// 协议定义
}

协议合成

Swift 支持合成多个协议,这在我们需要同时遵循多个协议时非常有用。

protocol Stname {
var name: String { get }
}

protocol Stage {
var age: Int { get }
}

struct Person: Stname, Stage {
var name: String
var age: Int
}

func show(celebrator: Stname & Stage) {
print("\(celebrator.name) is \(celebrator.age) years old")
}

let studname = Person(name: "Priya", age: 21)
print(studname)

let stud = Person(name: "Rehan", age: 29)
print(stud)

let student = Person(name: "Roshan", age: 19)
print(student)

检验协议的一致性

你可以使用isas操作符来检查是否遵循某一协议或强制转化为某一类型。

is操作符用来检查实例是否遵循了某个协议。

as?返回一个可选值,当实例遵循协议时,返回该协议类型;否则返回nil

as用以强制向下转型,如果强转失败,会引起运行时错误。

实例

protocol HasArea {
var area: Double { get }
}

// 定义了Circle类,都遵循了HasArea协议
class Circle: HasArea {
let pi = 3.1415927
var radius: Double
var area: Double { return pi * radius * radius }
init(radius: Double) { self.radius = radius }
}

// 定义了Country类,都遵循了HasArea协议
class Country: HasArea {
var area: Double
init(area: Double) { self.area = area }
}

// Animal是一个没有实现HasArea协议的类
class Animal {
var legs: Int
init(legs: Int) { self.legs = legs }
}

let objects: [AnyObject] = [
Circle(radius: 2.0),
Country(area: 243_610),
Animal(legs: 4)
]

for object in objects {
// 对迭代出的每一个元素进行检查,看它是否遵循了HasArea协议
if let objectWithArea = object as? HasArea {
print("面积为 \(objectWithArea.area)")
} else {
print("没有面积")
}
}