Swift协议
协议规定了用来实现某一特定功能所必需的
方法
和属性
类、结构体、枚举
类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。
能够满足协议要求的类型被称为遵循此协议
(一)协议的声明
协议的定义方式(关键词:protocol
):
protocol ProtocolName {
// 协议内容(声明属性/方法)
}
协议对属性声明的规定
协议用于指定特定的实例属性或类属性,而不用指定是存储型还是计算型的属性。必须要指明是只读的还是可读可写的属性
。
通常用var
关键词声名变量属性,在类型声明后面加{set get}
表示是可读可写属性,用{get}
表示只读属性
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}
}
//FirstClass类遵循secondProtocol协议,需要FirstClass类实现secondProtocol协议中的属性及方法
class FirstClass:secondProtocol {
//实现协议中的只读属性
let ranking = "第三名"
let name = "小明"
var english:Float = 78.50
var chinese = 88.0
var mathematics = 95.0
func minResults() -> String {
return "小明本次成绩数学是最高分95.0"
}
func maxResults() -> String {
return "小明本次成绩最低分是英语78.5"
}
}
调用
let student = FirstClass()
print("\(student.maxResults())")
调用结果
小明本次成绩最低分是英语78.5
协议对构造器的声明
协议是可以要求它的遵循者实现指定的构造器
在协议的定义中,不需要花括号及构造器的实体
*/
protocol ProtocolName {
init(someParameter: Int)
}
*/
protocol tcpprotocol {
init (aprot:Int)
}
协议中对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()
调用结果
Wednesday
(二)协议的实现
协议构造器在类中的实现
在遵循该协议的类中实现构造器,并指定其为类的指定构造器或便利构造器,必须给用"required"
修饰
//协议构造器的实现
class SomeClass: ProtocolName {
required init(someParameter: Int) {
// 构造器实现
}
}
protocol tcpprotocol {
init (aprot:Int)
}
class tcpClass:tcpprotocol {
required init(aprot: Int) {
print("实现指定构造器方法")
}
}
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)
}
//遵循协议,加上"required" 继承父类重写父类构造器加上"override"
required override convenience init(aprot: Int) {
self.init(num1: aprot, num2: 10)
}
}
调用
let tcp = tcpClass(aprot: 3)
print("实现协议方法:\(tcp)")
调用结果
实现指定构造器方法
实现协议方法:Swift_study.tcpClass
协议类型
,但是协议可以被当做类型使用
protocol TestProtocolA{
var num:Int{get set}
func calc(sum:Int)
}
protocol ResultProtocol{
//将协议TestProtocolA作为定义方法时的参数类型
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)
}
}
调用
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)
调用结果
大明尝试1次通过
大明尝试5次通过
大明尝试5次通过
大明缺席考试
大明尝试5次通过
大明缺席考试
在扩展中添加遵循的协议
扩展可以为已存在的类型添加 等成员
//在扩展中添加协议成员
enum ageType
{
case Baby,Child,Teenager,Young,Elderly,Normal
}
protocol AgeClasificationProtocol {
var age: Int { get }
func agecClassified() -> ageType
}
//创建Actor类
class Actor {
let firstname:String
let lastname:String
//很神奇,对Actor扩展时增加了AgeClasificationProtocol协议,在此实现协议里的属性、方法也是可以的(也可以在扩展中实现)
var age:Int
init(firstname:String,lastname:String) {
self.firstname = firstname;
self.lastname = lastname;
self.age = 13
}
}
//对Actor类扩展时添加AgeClasificationProtocol协议
extension Actor:AgeClasificationProtocol{
func fullname() -> String {
var name: String
name = firstname + " " + lastname
return name
}
//实现协议方法
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 函数类型的参数
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 "未知"
}
}
}
调用
let xiaoming = Actor(firstname: "王", lastname: "小明")
xiaoming.age = 12
let ageName = xiaoming.ageTypeName(typeFunc: xiaoming.agecClassified)
print("演员的全名:\(xiaoming.fullname())")
print("\(xiaoming.fullname()):所属的年龄段:\(ageName)")
调用结果
演员的全名:王 小明
王 小明:所属的年龄段:小孩儿
协议的继承
协议是能够继承其他协议,可以在继承的协议基础上增加新的内容要求。
语法:协议的继承语法与类的继承相似,
//protocol 新的协议名: 被继承的协议, 被继承的协议,其他被继承的协议 { // 增加的新的协议定义}
protocol NewProtocolName: SomeInheritingProtocol, AnotherInheritingProtocol {
// 增加的新的协议定义
}
例
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 "小明本次成绩数学是最高分95.0"
}
func maxResults() -> String {
return "小明本次成绩最低分是英语78.5"
}
}
调用
let student = FirstClass()
print("\(student.maxResults())")
调用结果
小明本次成绩最低分是英语78.5
定义类的专属协议
可以在协议的继承列表中,通过。
注意:class关键字必须是,其后,才是其他继承协议。
protocol SomeClassOnlyProtocol:
class,
SomeInheritedProtocol {
// 协议的定义内容
}
protocol TcpProtocol {
init(num:Int)
}
//用class修饰符在协议的继承列表中定义类的专属协议ExclusiveProtocol
protocol ExclusiveProtocol:class,TcpProtocol{
init(num1:Int,num2:Int)
}
//TcpProtocol协议可以被结构体遵循
struct School:TcpProtocol{
init(num: Int) {
print("市第\(num)中学")
}
}
//ExclusiveProtocol协议已经不能被结构体类型遵循了
/*
struct Hospital:ExclusiveProtocol {
init(num: Int) {
print("市第\(num)医院")
}
}
*/
//Hospital类遵循专属协议ExclusiveProtocol
class Hospital:ExclusiveProtocol{
var area:Int
var num:Int
init(area: Int, num: Int) {
self.area = area
self.num = num
print("\(area)区-\(num)号医院")
}
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)区-\(num)号医院")
}
required convenience init(num1: Int, num2: Int) {
self.init(address:"河北街",area: num1, num: num2)
}
required convenience init(num: Int) {
self.init(address:"河东街",area: num, num: 10)
}
}
调用
let hospital = Hospital(num: 8);
let hospital_a = CityHospital(address: "河西街", area: 1, num: 2)
let hospital_b = CityHospital(num: 6)
调用结果
5区-8号医院
1区-2号医院
河西街-1区-2号医院
6区-10号医院
河东街-6区-10号医院
协议的合成
,在需要同时遵循多个协议时很有用
protocol NameProtocol {
var name:String{get}
}
protocol AgeProtocol {
var age:Int{get}
}
//Worker遵循俩协议
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")
}
调用
let zhangzong = Worker(name:"老张", age: 45)
print(zhangzong)
showWorker(worker: zhangzong)
调用结果
Worker(name: "老张", age: 45)
老张 is 45 years old
检验协议的一致性
使用is
和as
操作符检查是否遵循某协议或强制转化为某一协议类型
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
}
}
调用
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("有\(pro.rooms)个房间")
}
调用结果
3
面积为:18.095573664
面积为:15.0
没有面积概念
没有面积概念
有3个房间