1.定义和语法
在swift中,protocol(协议)是为了完成某一特定任务而定义的一组方法和属性的蓝图(在OC中只能有方法不能有属性),可以作用于 class , struct, enumeration。
protocol SomeProtocol { // protocol deFinition goes here }
2. 语法
当自定义的类型需要遵守一个或多个协议时,结构如下:
class CustomType:SuperClass,Protocol1,Protocol2 {
}
3. 属性要求
在协议中添属性时, 属性必须是变量,而且必须指定其读写属性,不必关心其是计算属性还是存储属性, 如果是类属性只要在前面加上 "static"
protocol SomeProtocol { var mustBeSettable: Int { get set } var doesNotNeedToBeSettable: Int { get } static var someTypeProperty:Int { get set } } protocol FullNamed { var fullName:String {get} } class Person: FullNamed { var prefix:String? var name:String init(name:String,prefix:String?) { self.prefix = prefix self.name = name } var fullName:String { return (prefix != nil ? prefix! + name : name) } }
- 在一般情况下我们需要在遵守协议的自定义类型中实现所有的属性
4方法要求
跟OC一样,只需要在自定义的类型中实现协议中的方法即可。
注意: 当协议用于struct,enumeration时,如果协议中的实列方法需要改变该实例的属性时,需要在方法前面加上mutating关键字。
protocol FullNamed { var fullName:String {get} mutating func fixname() } struct boy:FullNamed { var prefix:String var name:String var fullName:String { return(prefix + name) } mutating func fixname() { self.name = "123" } } var b = boy(prefix: "China",name: "Barry") print(b.fullName) b.fixname() print(b.fullName)结果:
ChinaBarry
China123
5.可选属性与可选方法:
根据上面3,4结论,在协议中定义的方法我要必须全部实现,但这很不合理。在OC的协议中就存在可选方法。
在swift中我们可以定义具有可选的属性和方法,但是这样的协议只能用于class. 定义这样的协议时要在协议的定义前加上@objc
@objc public protocol FullNamed { func beautiful() optional var fullName:String {get} optional func fixname() } class Person:NSObject,FullNamed { var prefix:String? var name:String var age:Int func beautiful() { } init(name:String,prefix:String?) { self.prefix = prefix self.name = name self.age = 2 } }
上面的代码中 person继承于NSObject,但是如果Person没有继承于NSObject及其子类,那么就要在实现的方法前面加是@objc
class Person:FullNamed { var prefix:String? var name:String var age:Int @objc func beautiful() { } init(name:String,prefix:String?) { self.prefix = prefix self.name = name self.age = 2 } }
6. 在协议中添加初始化方法
在协议中可以添加一个初始化方法,这个方法在实现时需要加上关键字required。例如:我们自定一个类遵守了NSCoding协议,那么我们就必须在类中实现
在类Person中有一个 RandomProtocol类型的属性,任何遵守RandomProtocol协议的类的实例都可以作为RandomProtocol类型的实例。就像上面代码表现的一样,CreateNumber()和ResetNumber()都可以作为RandomProtocol类型的实例
publicinit?(coder aDecoder:NSCoder)
requiredinit?(coder aDecoder:NSCoder) {
super.init(coder: aDecoder)
}
当我们继承的父类也实现了这个方法是,我们就需要变成requiredoverride
7. 协议作为一种类型:
- 协议可以作为函数方法的参数以及返回类型
- 协议可以作为变量或常量的类型
- 数组,字典或其他的聚合类型可以保存的类型
protocol RandomProtocol { func getarandom()->Int } // 用于产生一个随机数,遵守RandomProtocol协议 class CreateNumber:RandomProtocol { func getarandom() -> Int { return random() } } // 返回一个0,遵守RandomProtocol协议 class ResetNumber:RandomProtocol { func getarandom() -> Int { return 0 } } class Person { let name:String! // 协议作为属性的类型 let random:RandomProtocol init(name:String,random:RandomProtocol) { self.name = name self.random = random } func outNumber()->Int { return self.random.getarandom() } } let p = Person(name: "iOS",random:CreateNumber()) print(p.outNumber()) let p1 = Person(name: "iOS",random:ResetNumber()) print(p1.outNumber())
在类Person中有一个 RandomProtocol类型的属性,任何遵守RandomProtocol协议的类的实例都可以作为RandomProtocol类型的实例。就像上面代码表现的一样,CreateNumber()和ResetNumber()都可以作为RandomProtocol类型的实例
8. 代理
遵守某个协议的类可以作为代理出现,只要用过tableView对这个再熟悉不过了。在tableView中有这样两个属性
weakpublicvar dataSource:UITableViewDataSource?
weak publicvar delegate:UITableViewDelegate?
当我们的UIViewcontroller加入tableView时,我们只需要让UIViewcontroller遵守UITableViewDelegate和UITableViewDataSourceDelegates就可以作为tableView的代理
tableView.
self.tableView.delegate =self
self.tableView.dataSource =self
9. 其他
- 定义只支持类的protocol
-
protocolSomeClassOnlyProtocol:class, SomeInheritedProtocol {
-
// class-only protocol deFinition goes here
-
}
- protocol 可以像普通类一样继承并且支持多继承
- 可以通过extension关键字让已存在的类遵守某个协议extension ClassName: protoclName。 当通过extension添加协议时,如果类中已经存在与协议中同名的方法时,extension协议的实现中可以不写这些方法。
protocol TextRepresentable { var textualDescription: String{get} } struct Hamster { var name: String var textualDescription: String { return "A hamster named \(name)" } } extension Hamster: TextRepresentable {}在Hamster中起初并未遵守TextRepresentable协议,但是却有一个与协议中属性同名的属性,所以在通过extension遵守属性时就不需要再次实现了。