Swift学习笔记20——协议(Protocols)

本文详细介绍了Swift中的协议,包括协议定义、协议的使用方式、构造器要求、协议作为类型、协议扩展、继承协议、遵守多个协议、实例判断及可选需求等核心概念,帮助开发者掌握面向协议编程的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

协议,就是一些规定。当一个类遵循了协议之后,它就必须满足协议所规定的内容。

使用协议的好处就是,以后我们可以面向协议编程。我们写的同一段代码可以针对不同的类型使用,只要这个类型遵循了我们所定义的协议。

协议定义语法

protocol SomeProtocol {
    // protocol definition goes here
}
类型实现协议的语法。类型可以是类、结构体、枚举类。协议写在父类的后面,用逗号分开。如果有多个协议,也用逗号分开。

class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
    // class definition goes here
}


属性要求

协议里面可以定义一些实例属性或类型属性,那么遵循这个协议的类型就必须提供这些属性。可以是用存储属性或计算属性提供。

假如协议里面定义的属性是可以读写的。那么类型必须提供可读写的属性。如果协议定义只读的,那么类型里面可以是读写的。

protocol FruitProtocol {
    static var name: String {get}
    var price: Int {set get}  //set 和 get 没顺序要求
}

class Apple: FruitProtocol {
    static var name: String = "apple"
    var price: Int {
        get {
            return 10
        }
        set {
            print("I don't want to change the price!!")
        }
    }
}

方法要求

protocol SomeProtocol {
    static func someTypeFunc()
    func someFunc()
    mutating func someMutatingFunc()
}

例子如上,协议里面的方法不用写方法体。如果是类型方法,加上关键字static。类在实现类型方法的时候,可以用class或static修饰。

注意最后一个实例方法,它加上了mutating关键字。这个主要是给值类型使用的。因为如果值类型在方法里面修改属性的话,必须用到mutating去修饰方法。如果是类实现这个协议的话,那么这个方法不用加mutating关键字。


构造器要求

protocol SomeProtocol {
    init(someParameter: Double)
    init?(someParameter: Int)
}
当一个类实现这种协议的时候,它如果不是一个final类(不允许继承),那么它在实现这些构造器的时候,构造器必须加上required关键字。

如果一个类实现协议的构造器刚好和父类的构造器是一样的,那么要同时加上required和override关键字。


Swift中的协议可以当做类型来使用
把协议当做类型使用,打个比方,就是把协议当做Int使用。Int能使用的地方,协议都可以使用。比如定义一个协议类型的变量。用协议类型的变量做函数的参数,返回值。

这里的用法和java是一样的。和OC不同。OC是用id<SomeProtocol>来代表一个实现协议的类型。

protocol SomeProtocol {
    init(someParameter: Double)
    init?(someParameter: Int)
}

var p: SomeProtocol? = nil
func someFunc(p: SomeProtocol) -> SomeProtocol {
    return p
}


利用扩展来实现协议

假如我们已经有了一个Animal类,但是不能获取到它的源代码。可以我们又想要它去遵守一定的协议,这时候可以用扩展为其添加协议。但是因为是扩展,所以还是不给添加存储属性。这时候必须用计算属性来实现协议。下面我们让Animal类实现上面的FruitProtocol协议。

extension Animal: FruitProtocol {
    var price: Int {
        get{
            return 23434
        }
        set {
            print("do nothing")
        }
    }
    static var name: String {
        return "animal"
    }
}
如果一个类在定义的时候已经满足某个协议的所有需求,那么可以使用extension显式指明它遵守了这个协议。这个时候,extension里面不用写什么。另外如果一个类满足了某个协议的需求,你不显式声明它遵守这个协议的话,它是不实现这个协议的。

继承协议

协议和类一样,是可以继承的。继承后的协议可以再添加一些属性和方法。如果需要继承多个协议,那么就用逗号分开多个协议。

protocol AnimalProtocol: FruitProtocol, SecondProtocol{
    var canRun: Bool {get}
    func makeSounds()
}

Class协议

如果你的协议只想用在类里面,那么可以声明它为一个Class协议。这种协议不能被值类型实现。语法就是在继承协议的冒号后面加上class关键字。没继承协议的话,后面的协议就不用写了。但是class关键字一定要写在被继承协议的前面。

protocol AnimalProtocol:class, FruitProtocol, SecondProtocol{
    var canRun: Bool {get}
    func makeSounds()
}


遵守多个协议

上面提到了,协议可以看成是一种类型,然后可以充当参数,返回值等等。但是有些时候想要一个参数同时满足多个协议。这个时候就不能用单个协议去充当参数了。这时候可以用一对<>号将多个协议连接起来。例子如下

func doSomething(para: protocol<FruitProtocol,SecondProtocol>) {
    //do something
}
这时候,para参数就必须同时遵守这两个协议才行。


判断实例是否遵守协议

is,这个is用于判断某个实例是否遵守了某个协议。

as?和as!。这个和类转换一样,用于将一个实例转换为某个协议类。如果这个实例遵守了这个协议,那么它就能被转换。


可选需求

上面所讲的所有定义在协议里面的东西都是必须实现的。但是有些情况下,我们想这些需求不一定要实现,而是可选地实现。这个时候就要用到可选需求。这个概念应该是直接利用了OC里面的概念来使用的。语法有两处:一处是@objc,一处是optional。

@objc protocol SecondProtocol {
    optional var time: Double {get}
    optional func doHomework()
}
关键字optional用来定义这个需求是不是可选的。

@objc一般是用于Swift和OC的混合编程。但是这里即使你没有使用到混合编程,如果想要实现可选需求,还是必须加上@objc。

使用到可选需求的时候要注意一点奇怪的事情。

第一,实现带有@objc的协议的时候,实现的内容上必须加上@objc。否则报错。这个@objc可以加在实现的属性和方法上,也可以加在类的声明关键字的最前面,但是后一种方法要求这个类必须是NSObject的子类。

第二,如果是在类扩展里面实现带有@objc的协议,只能在实现的内容上面加上@objc。

第三条,估计是个bug,当你定义一个继承自可选协议A的协议B。然后让类C实现这个协议B,用is判断C的实例是否是A的类型,照理来讲应该是true。可是这里会出现runtime Error。


扩展协议

这个和扩展类是一样的。但是这里并不是协议,里面的属性和方法都必须按照扩展的要求来写:方法要有方法体,不能有存储属性。协议扩展里的东西对实现了该协议的类都会有扩展作用。

extension AnimalProtocol {
    var canFly: Bool {
        get{
            return false
        }
    }
}
注意,如果你用协议扩展对协议的必须方法或属性做了默认的定义。那么类在实现这个协议的时候,不必实现已经实现的协议要求。但如果实现了,协议扩展里面实现的内容都会被类里面的定义覆盖。


Swift仍需改进。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值