协议(Protocol)

协议可以用来定义方法、属性、下标的声明,协议可以被枚举、结构体、类遵守(多个协议之间用逗号隔开)

  1. protocol Test {
  2. func play()
  3. var x: Int { get set}
  4. var y: Int { get }
  5. subscript(index: Int) -> Int { get set }
  6. }
  1. protocol Test1 {}
  2. protocol Test2 {}
  3. protocol Test3 {}
  4. class Test : Test1, Test2, Test3 {}

协议中定义方法时不能有默认参数值
默认情况下,协议中定义的内容必须全部都实现(也有办法办到只实现部分内容)

协议中的属性

  1. protocol Test {
  2. func play()
  3. var x: Int { get set}
  4. var y: Int { get }
  5. subscript(index: Int) -> Int { get set }
  6. }
  7. class Person : Test {
  8. // 通过存储属性实现协议的属性
  9. var x: Int = 0
  10. var y: Int = 0
  11. func play() {
  12. }
  13. subscript(index: Int) -> Int {
  14. set {}
  15. get { return index }
  16. }
  17. }
  18. class Student : Test {
  19. // 通过计算属性实现协议的属性
  20. var x: Int{
  21. get { 0 }
  22. set { }
  23. }
  24. var y: Int {
  25. get { 0 }
  26. }
  27. func play() {
  28. }
  29. subscript(index: Int) -> Int {
  30. set {}
  31. get { return index }
  32. }
  33. }
  • 协议中定义属性必须用var关键字
  • 实现协议时的属性权限要不小于协议中定义的属性权限:

协议定义get、set,用var存储属性或get、set计算属性去实现
协议定义get,用任何属性都可以实现

static、class

为了保证通用,协议中必须使用static定义类型方法、类型属性、类型下标

  1. protocol Test1 {
  2. static func play()
  3. }
  4. class Person : Test1 {
  5. static func play() {
  6. }
  7. }
  8. struct Student: Test1 {
  9. static func play() {
  10. }
  11. }
  12. class Dog : Test1 {
  13. class func play() {
  14. }
  15. }

为了保证类、结构体、枚举都能实现协议中的类型方法,所以需要使用static修饰类型方法。
类中实现类型方法时,可以使用static也可以使用class,看是否允许子重写。

mutating

只有将协议中的实例方法标记为mutating:
才允许结构体、枚举的具体实现修改自身内存
类在实现方法时不用加mutating,枚举、结构体才需要加mutating

  1. protocol Test {
  2. mutating func play()
  3. }
  4. class Person : Test {
  5. var width: Int = 0
  6. func play() {
  7. width = 10
  8. }
  9. }
  10. struct Student : Test {
  11. var x: Int = 0
  12. mutating func play() {
  13. x = 10
  14. }
  15. }

init

协议中还可以定义初始化器init
非final类实现时必须加上required

  1. protocol Test {
  2. init(x: Int, y: Int)
  3. }
  4. class Person : Test {
  5. required init(x: Int, y: Int) {
  6. }
  7. }
  8. final class Student : Test {
  9. init(x: Int, y: Int) {
  10. }
  11. }

之所以非final类实现协议中初始化器需要加上required,是因为保证子类也需要实现该方法。
如果从协议实现的初始化器,刚好时重写了父类的指定初始化器,那么初始化必须同时加required、override

  1. protocol Test {
  2. init(age: Int)
  3. }
  4. class Person {
  5. init(age: Int) {}
  6. }
  7. class Student: Person, Test {
  8. required override init(age: Int) {
  9. super.init(age: age)
  10. }
  11. }

init、init?、init!

协议中定义的init?、init!,可以用init、init?、init!去实现
协议中定义的init,可以用init、init!去实现

  1. protocol Test {
  2. init()
  3. init?(age: Int)
  4. init!(name: String)
  5. }
  6. class Person : Test {
  7. // 实现 init()
  8. required init() {}
  9. // 或 required init!() {}
  10. // 实现 init?(age: Int)
  11. required init?(age: Int) {}
  12. // 或 required init!(age: Int) {}
  13. // 或 required init(age: Int) {}
  14. // 实现 init!(name: String)
  15. required init!(name: String) {}
  16. // 或 required init?(name: String) {}
  17. // 或 required init(name: String) {}
  18. }

协议的继承

一个协议可以继承其他协议

  1. protocol Sport {
  2. func run()
  3. }
  4. protocol Music : Sport {
  5. func sing()
  6. }
  7. class Person : Music {
  8. func run() {
  9. }
  10. func sing() {
  11. }
  12. }

协议组合

协议组合,可以包含1个类类型(最多1个)

  1. protocol Sport { }
  2. protocol Music { }
  3. class Person { }
  4. // 接收Person或者其子类的实例
  5. func fn1(obj: Person) {}
  6. // 接收遵守Sport协议的实例
  7. func fn2(obj: Sport) {}
  8. // 接收同时遵守Sport和Music协议的实例
  9. func fn3(obj: Sport & Music) {}
  10. // 接收同时遵守Sport和Music协议、并且是Person或者其子类的实例
  11. func fn4(obj: Person & Sport & Music) {}
  12. // 也可以设置别名
  13. typealias NewPerson = Person & Sport & Music
  14. // 接收同时遵守Sport和Music协议、并且是Person或者其子类的实例
  15. func fn5(obj: NewPerson) {}

CaseInterable

让枚举遵守CaseIterable协议,可以实现遍历枚举

  1. enum Season : CaseIterable {
  2. case spring
  3. case summer
  4. case autumn
  5. case winter
  6. }
  7. let seasons = Season.allCases // [Season]
  8. for season in seasons {
  9. print(season)
  10. }
  11. // spring summer autumn winter

遵守CaseIterable协议后,可以使用allCases遍历枚举。

CustomStringConvertible

继承CustomStringConvertible协议后,可以重写description计算属性,在打印实例对象时,就会输出description的内容

  1. class Person : CustomStringConvertible {
  2. var age: Int = 0
  3. var description: String {
  4. get {
  5. "I am a person, age \(age)."
  6. }
  7. }
  8. }
  9. var p = Person()
  10. print(p)

CustomDebugStringConvertible协议和CustomStringConvertible类似:

  1. class Person : CustomDebugStringConvertible {
  2. var age: Int = 0
  3. var debugDescription: String {
  4. get {
  5. "I am a person, age \(age)."
  6. }
  7. }
  8. }
  9. var p = Person()
  10. debugPrint(p)

print调用的是CustomStringConvertible协议的description
debugPrint、po调用的是CustomDebugStringConvertible协议的debugDescription
image.png

Any、AnyObject

Swift提供了两种特殊的类型:Any、AnyObject
Any:可以代表任意类型(枚举、结构体、类,也包括函数类型)
AnyObject:可以代表任意类类型(在协议后面写上:AnyObject代表只有类能遵守这个协议)
image.png
Any类型的变量,赋值不同类型不会报错

  1. var num: Any = 10
  2. num = "10"
  3. num = NSObject()

创建1个能存放任意类型的数组

  1. var arr = [Any]() // 或var arr = Array<Any>()
  2. arr.append(1)
  3. arr.append(0.5)
  4. arr.append("abc")
  5. arr.append({ 10 })// 闭包表达式

is、as?、as!、as

is用来判断是否为某种类型,as用来做强制类型转换
is使用:

  1. protocol Sport { func run() }
  2. class Person {}
  3. class Student : Person, Sport {
  4. func run() {}
  5. func study() {}
  6. }
  7. var stu: Any = 1
  8. print(stu is Int) // true
  9. stu = "Jack"
  10. print(stu is String) // true
  11. stu = Student()
  12. print(stu is Student) // true
  13. print(stu is Person) // true
  14. print(stu is Sport) // true

as?和as!使用:

  1. var stu: Any = 10
  2. (stu as? Student)?.study() // 没有调用study()
  3. //(stu as! Student).study() // 隐式解包会导致报错
  4. stu = Student()
  5. (stu as? Student)?.study() // 调用了study()
  6. (stu as! Student).study() // 调用了study()
  7. (stu as? Sport)?.run() // 调用了run()

as使用:

  1. var data = [Any]()
  2. data.append(Int("123") as Any)

*肯定能转换成功的情况下使用as

X.self、X.Type、AnyClass

X.self是一个元类型(metadata)的指针,metadata存放着类型相关信息
image.png
X.self属于X.Type类型

  1. class Person {}
  2. class Student : Person {}
  3. var pType: Person.Type = Person.self
  4. var sType: Student.Type = Student.self
  5. pType = Student.self

*最后一句成立是因为Student继承与Person,所以Student.self也属于Person.Type

AnyClass

  1. // AnyClass的系统定义
  2. public typealias AnyClass = AnyObject.Type
  1. // 因为AnyObject代表任意类,所以AnyObject.Type可以是所有类.self的类型
  2. var anyType1: AnyObject.Type = Person.self
  3. anyType1 = Student.self
  4. // AnyClass和AnyObject.Type的意义一样
  5. var anyType2: AnyClass = Person.self
  6. anyType2 = Student.self

类型判断

  1. var p = Person()
  2. var pType = type(of: p) // Person.self
  3. print(Person.self == type(of: p)) // true

*type(of: ) 的本质是读取对象的前8个字节出来,底层不是函数

元类型的应用

1、通过元类型快速创建子类实例对象

  1. class Animal {
  2. required init() {}
  3. }
  4. class Dog : Animal {}
  5. class Cat : Animal {}
  6. class Pig : Animal {}
  7. func create(_ clsArr: [Animal.Type]) -> [Animal] {
  8. var arr = [Animal]()
  9. for cls in clsArr {
  10. arr.append(cls.init())
  11. }
  12. return arr
  13. }
  14. print(create([Cat.self, Dog.self, Pig.self]))

打印结果:

  1. [SwiftTest.Cat, SwiftTest.Dog, SwiftTest.Pig]

2、通过元类型获取父类

  1. class Person {}
  2. class Student : Person {}
  3. print(class_getSuperclass(Student.self)!) // Person
  4. print(class_getSuperclass(Person.self)!) // _TtCs12_SwiftObject

从结果可以看出来,Swift还有个隐藏的基类SwiftObject,可以通过Swift源码查看:https://github.com/apple/swift/blob/main/stdlib/public/runtime/SwiftObject.h

  1. #if SWIFT_OBJC_INTEROP
  2. #if __OBJC__
  3. // Source code: "SwiftObject"
  4. // Real class name: mangled "Swift._SwiftObject"
  5. #define SwiftObject _TtCs12_SwiftObject
  6. #if __has_attribute(objc_root_class)
  7. __attribute__((__objc_root_class__))
  8. #endif
  9. SWIFT_RUNTIME_EXPORT @interface SwiftObject<NSObject> {
  10. @private
  11. Class isa;
  12. SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
  13. }

Self

Self一般用作返回值类型,限定返回值跟方法调用者必须是同一种类型(也可以作为参数类型)

  1. protocol Test {
  2. func test() -> Self
  3. }
  4. class Person : Test {
  5. required init() {}
  6. func test() -> Self {
  7. type(of: self).init()
  8. }
  9. }
  10. class Student : Person {}
  11. var p = Person()
  12. print(p.test()) // Person
  13. var stu = Student()
  14. print(stu.test()) // Student

如果Self用在类中,要求返回时调用的初始化器是required的
Self代表当前类型

  1. class Person {
  2. var age = 1
  3. static var count = 2
  4. func run() {
  5. // 小写self
  6. print(self.age) // 1
  7. // 大写Self
  8. print(Self.count) // 2
  9. }
  10. }