热点新闻
Swift基础语法(九)协议和元类型
2023-07-17 20:18  浏览:6835  搜索引擎搜索“微商筹货网”
温馨提示:信息一旦丢失不一定找得到,请务必收藏信息以备急用!本站所有信息均是注册会员发布如遇到侵权请联系文章中的联系方式或客服删除!
联系我时,请说明是在微商筹货网看到的信息,谢谢。
展会发布 展会网站大全 报名观展合作 软文发布

Swift基础学习文章汇总

本文主要介绍了Swift中协议的使用以及几个常见协议,还有类型判断(is)和强转(as)的使用和元类型

主要内容:

  1. 协议的使用
  2. 常见协议
  3. 类型判断和强转
  4. 元类型

1. 协议的使用

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

1.1 基本定义

代码:

protocol Drawable { func draw() var x: Int { get set } var y: Int { get } subscript(index: Int) -> Int {get set} }

说明:

  • 协议只能定义,不能有任何的实现
  • 协议中定义方法时不能有默认参数值,因为协议没有任何实现
  • 默认情况下,协议中定义的内容必须全部实现

1.2 关键字

static:
代码:

//static 可以看到类中可以使用static也可以使用class,struct只能使用static protocol Drawable2 { static func draw() } class Person1 : Drawable2 { class func draw(){ print("Person1 draw") } } class Person2 : Drawable2 { static func draw() { print("Person2 draw") } } struct Person3 : Drawable2 { static func draw() { print("Person3 draw") } } Person1.draw() Person2.draw() Person3.draw()

说明:

  • 为了保证通用,协议中必须用static定义类型方法、类型属性、类型下标
  • 因为协议可以被枚举、结构体、类遵守,而class只能在类中使用,所以必须使用static
  • 当然遵守该协议的类的该类型方法依然可以使用class

mutating
代码:

//mutating 类本身就可以进行修改,不需要mutating标记,结构体需要使用mutating标记 protocol Drawable3 { mutating func draw() } class Size: Drawable3 { var width: Int = 0 func draw() { width = 10 } } struct Point : Drawable3 { var x: Int = 0 mutating func draw() { x = 10 } }

说明:

  • 同样,只有将协议中的实例方法标记为mutating才允许结构体在该方法中修改存储属性值

1.3 属性

代码:

protocol Drawable4 { func draw() var x: Int { get set} var y: Int { get } subscript(index: Int) -> Int { get set } } class Person31: Drawable4 { var x: Int = 0 let y: Int = 0 func draw() { print("Person31 draw") } subscript(index: Int) -> Int { set { } get { index } } } class Person32: Drawable4 { var x: Int { get { 0 } set { } } var y: Int { 0 } func draw() { print("Person32 draw") } subscript(index: Int) -> Int { set { } get { index } } }

说明:

  • 这里的属性并没有说明是存储属性还是计算属性,只是说明可读可写
  • 可读可写的属性,既可以是存储属性,也可以是计算属性
  • 这里对于x和y都有两种实现方式,可能是存储属性可能是计算属性
  • 协议中定义属性时必须用var属性,因为无法预知它是存储属性还是计算属性
  • 实现协议时的属性权限不能小于协议中定义的属性权限,也就是说协议中定义的东西我们必须要实现,在此基础上想要增加实现也是可以的

1.4 init

协议中还可以定义初始化器,遵守该协议的类以及子类都必须实现初始化器,所以需要使用required来修饰。

代码:

protocol Livable { init(age: Int) } class Person41 { init(age: Int) { print("Person init") } } class Student: Person41, Livable { required override init(age: Int) { super.init(age: age) print("Student init") } } //Person init //Student init let stu = Student.init(age: 10)

说明:

  • 非final类实现时必须加上required
  • 如果从协议实现的初始化器,刚好是重写了父类的指定初始化器,那么这个初始化必须同时加required、override

init、init?、init!的区别

protocol Livable2 { init() init?(age: Int) init?(no: Int) } class Person42: Livable2 { required init() { print("Person42 init") } required init?(age: Int) { print("Person42 init?") } required init!(no: Int) { print("Person42 init!") } } let p1 = Person42.init() let p2 = Person42.init(age: 10) let p3 = Person42.init(no: 100) print(p1.self) print(p2.self) print(p3.self)

说明:

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

1.5 协议的继承

代码:

protocol Runnable { func run() } protocol Livable : Runnable { func breath() } class Person : Livable { func breath() {} func run() {} }

1.5 协议的组合

代码:

protocol Livable6 {} protocol Runnable6 {} class Person6 {} // 1、接收Person或者其子类的实例 func fn0(obj: Person6) {} // 2、接收遵守Livable协议的实例 func fn1(obj: Livable6) {} // 3、接收同时遵守Livable、Runnable协议的实例 func fn2(obj: Livable6 & Runnable6) {} // 4、接收同时遵守Livable、Runnable协议、并且是Person或者其子类的实例 func fn3(obj: Person6 & Livable6 & Runnable6) {} //5、也可以直接定义一下使用 typealias RealPerson = Person6 & Livable6 & Runnable6 // 接收同时遵守Livable、Runnable协议、并且是Person或者其子类的实例 func fn4(obj: RealPerson) {}

说明:

  • 协议可以组合起来遵守,和其他语言的差不多
  • 但是要注意写法,遵守协议的实例和类的实例写法是一样的

2. 常见协议

2.1 CaseIterable

代码:

enum Season : CaseIterable { case spring, summer, autumn, winter } let seasons = Season.allCases print(seasons.count) // 4 for season in seasons { print(season) } // spring summer autumn winter

说明:

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

2.2 CustomStringConvertible

代码:

//CustomStringConvertible ,自定义打印字符串 //CustomDebugStringConvertible,打印debug字符串 class Person : CustomStringConvertible, CustomDebugStringConvertible { var age = 0 var description: String { "person_\(age)" } var debugDescription: String { "debug_person_\(age)" } } var person = Person() print(person) // person_0 debugPrint(person) // debug_person_0

说明:

  • 遵守CustomStringConvertible、 CustomDebugStringConvertible协议,都可以自定义实例的打印字符串
  • print调用的是CustomStringConvertible协议的description
  • debugPrint、po调用的是CustomDebugStringConvertible协议的debugDescription

3. 类型判断和强转

3.1 任意类型认识

包括Any、AnyObject、AnyClass三种,Any表示任意类型,包括枚举、结构体、类、函数类型。AnyObject表示任意的类,AnyClass表示任意类的类型

Any实现

var stu81: Any = 10 stu81 = "Jack" var stu82: AnyObject = person stu82 = Person42() var classType: AnyClass = Person.self

说明:

  • stu的类型是Any,因此可以是数值、也可以是字符串、也可以是对象
  • AnyObject表示任意的类
  • AnyClass表示任意类的类型

3.2 类型判断

代码:

protocol Runnable9 { func run() } class Person9 { } class Student9 : Person9, Runnable9 { func run() { print("Student run") } func study() { print("Student study") } } //is var stu9: Any = 10 print(stu9 is Int) // true stu9 = "Jack" print(stu9 is String) // true stu9 = Student9() print(stu9 is Person9) // true print(stu9 is Student9) // true print(stu9 is Runnable9) // true

说明:

  • 可以看到is可以判断一个变量是否属于某个类型
  • is后面可以放协议、父类,编译器也是可以判断的

3.3 类型强转

代码:

//as var stu92: Any = 10 (stu92 as? Student9)?.study() // 返回nil,不会调用study stu92 = Student9() (stu92 as? Student9)?.study() // 解包,Student study (stu92 as! Student9).study() // 自动解包 ,可能会报错 Student study (stu92 as? Runnable9)?.run() // 解包,Student run

说明:

  • as用来进行类型强转的
  • 如果可以确定这个类型没有nil,那么可以用as
  • 如果强化失败就会返回nil
  • 如果有可能是nil,那么类型是可选项。就需要用as? 和 as!
  • 我们尽量用as?,这样可以避免报错,如果用as!自动解包的话如果是nil就会报错

4. 元类型

4.1 元类型的认识

代码:
元类型其实就是类的类型

class Person10 {} class Student10 : Person10 {} var perType: Person10.Type = Person10.self//拿到Person10的类型赋值给perType变量 var stuType: Student10.Type = Student10.self perType = Student10.self//因为是继承关系,所以可以这样赋值 var anyType: AnyObject.Type = Person10.self anyType = Student10.self//任意类型 public typealias AnyClass = AnyObject.Type var anyType2: AnyClass = Person10.self anyType2 = Student10.self var per = Person10() var perType2 = type(of: per) // Person.self print(Person10.self == type(of: per)) // true

说明:

  1. x.Type属于类类型,X.self是类型指针,类型指针赋值给类类型的
  2. 这里可以看到Person是类,Person.Type是类的类型
  3. 这个type()并不是函数调用
  4. type(of:p)得到的其实就是Person.self。也就是元类型的地址
  5. 因此pType的类型是Person.Type。

4.2 元类型应用

这里通过类类型可以同时对类进行处理
代码:

//应用 class Animal { required init() {} } class Cat : Animal {} class Dog : Animal {} class Pig : Animal {} func create(_ clses: [Animal.Type]) -> [Animal] { var arr = [Animal]() for cls in clses { arr.append(cls.init()) } return arr } print(create([Cat.self, Dog.self, Pig.self]))

4.3 Self关键字

Self表示当前类型,self表示当前对象,需要注意区分
代码:

protocol Runnable { func test() -> Self } class Person : Runnable { required init() {} func test() -> Self { type(of: self).init() } } class Student : Person {}

说明:
1、因继承关系中都可以使用,必须使用required
2、返回类型为了在继承中匹配使用Self
3、type(of: self).init()这种方式也是为了继承中匹配类型

发布人:35a6****    IP:101.229.64.***     举报/删稿
展会推荐
让朕来说2句
评论
收藏
点赞
转发