协议
swift中协议中可以声明属性,静态属性,方法,静态方案
protocol IPerson {
//属性 协议总是用 var 关键字来声明变量属性,
//在类型声明后加上 { set get } 来表示属性是可读可写的,可读属性则用 { get } 来表示:
var name:String{get set}
//static属性
static var address:String{get set}
//方法
func eat()
//static方法
static func helloWord()
}
class Chinese: IPerson {
var name: String = ""
static var address: String = "china"
func eat() {
print("Chinese eating now......")
}
static func helloWord() {
print("helloWord......")
}
}
子类如果继承了协议而不去实现其中的内容,编译就会通不过
协议的extension实现
在Swift中 协议可以直接由协议的extension实现,继承协议的子类可以直接调用,看Demo
protocol IPerson {
}
extension IPerson
{
func speak()
{
print("speaking now......")
}
}
class Chinese: IPerson {
}
let anson = Chinese()
anson.speak()
如代码所示,我们甚至在IPerson不声明speak函数,子类就能调用
可选的协议
协议可以定义可选要求,遵循协议的类型可以选择是否实现这些要求。在协议中使用 optional 关键字作为前缀来定义可选要求。可选要求用在你需要和 Objective-C 打交道的代码中。协议和可选要求都必须带上@objc属性。标记 @objc 特性的协议只能被继承自 Objective-C 类的类或者 @objc 类遵循,其他类以及结构体和枚举均不能遵循这种协议。
@objc protocol IAnimal {
@objc optional func sprak()
@objc optional var name:String{get}
@objc optional func variety() -> String
}
class Dog: IAnimal
{
func jump() {
print("Dog jump....")
}
var name: String{
return "dog"
}
func variety() -> String {
return "black"
}
}
let dog:IAnimal = Dog()
print(dog.name ?? "")
print(dog.variety!())
协议中的可选要求可通过可选链式调用来使用,因为遵循协议的类型可能没有实现这些可选要求。
需要注意的是整个函数类型是可选的,而不是函数的返回值。
associatedtype
在Swift中,class、struct、enums都可以是用参数化类型来表达泛型的,只有在协议中需要使用associatedtype关键字来表达参数化类型
协议在Swift中有两个目的,第一个目的是用来实现多继承(swift语言被设计为单继承的),第二个目的是强制实现者必须准守自己所指定的泛型约束。关键字associatedtype是用来实现第二个目的的
泛型的实现方式
下面例子中的associatedtype实现了类似泛型的作用
protocol ICooker {
associatedtype foodType
func barbecue(food:foodType) //烤*
func saute(food:foodType) //炒*
}
class Chicken {}
class Corn {}
//高级厨师可以烤肉或者炒肉
class SuperCooker: ICooker {
typealias FoodType = Chicken
func barbecue(food:FoodType) //烤肉
{
}
func saute(food:FoodType) //炒肉
{
}
}
//一般厨师只会烤玉米或者炒玉米
class GeneralCooker: ICooker {
typealias FoodType = Corn
func barbecue(food:FoodType) //烤玉米
{
}
func saute(food:FoodType) //炒玉米
{
}
}
判断是否符合协议
这个直接看代码
protocol ITest {
var name:String {get set}
}
class Test: ITest {
var name = "I am Test"
}
class Dog {
var name = "I am dog"
}
let arr:[AnyObject] = [Dog(),Test()]
arr.forEach { (item) in
if let item = item as? ITest { //用强转来判断
print("find ITest: " + item.name)
} else {
print("not find")
}
}
输出
not find
find ITest: I am Test
协议的约束
限定允许集成协议的类型
protocol 后面加上约束关键字【where】,并注明该协议只能被某个类(包括子类)所遵守
比如
class Person {}
protocol IPerson where Self : Person {}
extension IPerson
{
}
class Chinese: Person,IPerson {}
//class Dog:IPerson{} 编译不通过
上面的Dog继承IPerson 编译器报错'IPerson' requires that 'Dog' inherit from 'Person'
这个限定对于协议也可以
protocol ISpeak {}
protocol IPerson where Self : ISpeak {}
extension IPerson
{
}
class Chinese: ISpeak,IPerson {}
//class Dog:IPerson{} //编译不通过
上面的 Chinese继承了ISpeak协议,符合IPerson协议的条件,所以能编译通过 Dog未继承ISpeak协议,编译失败
对具体类型的扩展
上面的例子约束了子类的类型,编译器会帮我们去判断这个约束,但是有的时候我们需要对不同的类进行不同的扩展方法
比如下面
protocol ISpeak {}
class Chinese: ISpeak {}
class Dog:ISpeak{}
我想给Chiese和Dog不同的speak方法实现,那么可以这样
protocol ISpeak {}
class Chinese: ISpeak {}
class Dog:ISpeak{}
extension ISpeak where Self : Chinese
{
func speak()
{
print("Hollo word!")
}
}
extension ISpeak where Self : Dog
{
func speak()
{
print("wang wang wang~~~")
}
}
Chinese().speak()
Dog().speak()
输出
Hollo word!
wang wang wang~~~
这里利用了协议的extension的约束对不同的子类进行了扩展