HR's Blog

Swimming 🏊 in the sea🌊of code!

0%

Protocol

.

Protocol is name type, structs ,classes, and enums also name type. A protocol can be adopted by a class, struct, or enum.

Swift中默认所有的方法都是必须实现是的

1
2
3
4
5
protocal Vehicle {
func accelerate()
func stop()
var value: Double {get set}
}
  • 协议可以被classstructenum所遵守。
  • 协议里的方法不能包含默认值。
  • 如果要定义Optional的值,需要提供两个方法。 fun turn()fun turn(_ value:valueType)

Protocol inheritance

1
2
3
4
protocol WheeledVehicle: Vehicle {
var numberOfWheels: Int {get}
var wheelSize: Double { get set}
}

Implementing properties

当协议里面定义必须实现的值的get或者set方法。该值既可以是stored property 也可以是 computed property。而如果协议之要求你实现get方法,你的参数可以实现getset方法一起。

Associated Types in protocols

你可以用associated type关键字来定义协议要用到的相关类型,有点类似函数的泛型

1
2
3
4
protocol WeightCalculatable {
associatedtype WeightType
var weight: WeightType {get}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class HeavyThing: WeightCalculatable {
// This heavy thing only needs integer accuracy
typealias WeightType = Int

var weight: Int {
return 100
}
}

class LightThing: WeightCalculatable {
// This light thing needs decimal places
typealias WeightType = Double

var weight: Double {
return 0.0025
}
}

我们用typealias关键字解释WeightType是什么类型,这个通常是不需要写的。

Implementing multiple protocols

1
2
3
class Bike: Vehicle, Wheeled {
//Implement both Vehicle and Wheeled
}

Protocol Composition

In the previous section you learned how to implement multiple protocols. Sometimes you need a function to take a data type that must conform to multiple protocols. That is where protocol composition comes in. Imagine you need a function that needs access to the Vehicle protocol’s stop() function and the Wheeled protocol’s numberOfWheels property. You can do this using the & composition operator.

1
2
3
4
5
6
7
func roundAndRound(transportation: Vehicle & Wheeled) {
transportation.stop()
print("The brakes are being applied to \(transportation.numberOfWheels) wheels.")
}

roundAndRound(transportation: Bike())
// The brakes are being applied to 2 wheels.

Extensions and protocol conformance

可以用类的扩展来遵守也写,即使是像String这样的类,我们也可以通过这个方法让String来遵守一些协议。

1
2
3
4
5
6
7
8
9
protocol Reflective {
var typeName: String { get }
}

extension String: Reflective {
var typeName: String {
return "I'm a String"
}
}

两个好处

  1. 可以让一些系统类来遵守你的协议
  2. 可以把一些协议的实现定义在扩展里面,让代码看起来不那么乱

最近Swift版本可以在协议里面访问该类的私有变量
你不能在扩展里面定义stored properties但是你仍然可以通过在原来的类中定义stored properties来满足你在扩展里面协议需要实现的参数。

Requiring Reference semantics

因为协议能够被types type(structs 和 enums)遵守和reference type类型(classes)所遵守,所以对于structsclasses复制时不同的处理方式,你可能想要某些协议限制只能被classes所遵守。

1
2
3
protocol Named: class {
var name: String { get set }
}

Protocols in the standard library

Equatable

当你要用==比对两个自定义的对象是否相等的时候,你需要是显示系统的Equatable协议

1
2
3
protocol Equatable {
static func =(lhs: self, rhs: self) -> Bool
}

你需要在你的协议里面遵守该协议,如果你想比对你定义的协议是否相等,在方法里给出Bool值,来判断两个自定义的对象是否相等。

Comparable

Comparable类似==,提供了<,<=,>>=来比对你自定义的对象。
你只需要实现<==,其他的运算方法标准库会为你自动实现。

1
2
3
4
5
6
protocol Comparable: Equatable {
static func <(lhs: Self, rhs: Self) -> Bool
static func <=(lhs: Self, rhs: Self) -> Bool
static func >=(lhs: Self, rhs: Self) -> Bool
static func >(lhs: Self, rhs: Self) -> Bool
}

Freefunctions

当你为你的类实现了==<协议,那么系统会自动为你实现其他的方法例如

1
2
3
4
leagueRecords.max() // {wins 23, losses 8}
leagueRecords.min() // {wins 14, losses 11}
leagueRecords.starts(with: [teamA, teamC]) // true //这个没有明白是什么意思
leagueRecords.contains(teamA) // true

Hashable

HashableEquatable的子类,任何你要用作为Dictionary字典的Key都需要遵守该协议。

1
2
3
protocol Hashable : Equatable {
var hashValue: Int {get}
}

Hashable可以快速帮你在集合中找到元素,所以==true的值,那么Hash值应该是一样的。

一般用==比对的值来发挥相同的hash值,例如student对象里面name,我们可以用name来判断该学生是否为同一个学生,也可以用name的hash值来当做整个student对象的hash值

CustomStringConvertible

CustomStringConvertible提供你print自定义对象时候的内容。

1
2
3
protocol CustomStringConvertible {
var description: String { get }
}

CustomDebugStringConvertibaleCustomStringConvertible非常相识,只是互相对应的debugPrintprint方法

Objective-C 中的Optional选项

对于Swift中的Optional的值,我觉得可以在Swift中通过继承的方式来实现。

原生的Swift protocol里没有可选值,所有定义的方法都必须实现的。如果我们想要像Objective-C里那样定义可选的接口方法,就需要将接口本身定义为Objective-C的,也即在protocol定义之前加上@objc。另外和Objective-C中的@Optional不同,我们使用没有@符号的关键字optional来定义可选方法:

1
2
3
4
5
6
7
8
9
10
11
@objc protocol viewDelegate {
optional func viewClike()
}
class view:NSObject {
var delegate:viewDelegate?

func clickFunc() {
delegate?.viewClick()
}

}