Swift全解析

文章26 |   阅读 17234 |   点赞0

来源:https://blog.csdn.net/u010586842/category_9264386.html

Swift详解之六----------------枚举、结构体、类

x33g5p2x  于2022-03-08 转载在 其他  
字(3.9k)|赞(0)|评价(0)|浏览(634)

枚举、结构体、类

注:本文为作者自己总结,过于基础的就不再赘述 ,都是亲自测试的结果。如有错误或者遗漏的地方,欢迎指正,一起学习。

1、枚举

枚举是用来定义一组通用类型的一组相关值 ,关键字enum ,case关键词表明新的一行成员值将被定义。

  1. enum Direction{
  2. case East
  3. case West
  4. case South
  5. case North
  6. }

这里定义了一个简单的枚举类型 , 里面有四个枚举元素 。
也可以用一行的形式

  1. enum Direction{
  2. case East , West , South , North
  3. }

可以这样来访问这个枚举类型var dir = Direction.East ,这时候这个变量 dir 已经被推断成Direction ,重新赋值的时候 可以直接用短语法dir = .West

  • 相关值(Associated Values)
    你可以定义 Swift 的枚举存储任何类型的相关值,如果需要的话,每个成员的数据类型可以是各不相同的。
  1. enum Barcode {
  2. case UPCA(Int , Int , Int ,Int )
  3. case QRCode(String)
  4. }

你可以这样给它赋值var pro = Barcode.UPCA(8, 53627, 29009, 1) ,也可以这样修改pro = .QRCode("DSLEKWLJELJAIWFLWKJF")

这样取值

  1. switch pro{
  2. case .UPCA(let a1,let a2, let a3, let a4):
  3. print("\(a1) , \(a2) , \(a3) , \(a4)")
  4. case .QRCode(let s):
  5. print(s)
  6. }

你也可以把let写在最前面

  1. switch pro{
  2. case let .UPCA( a1, a2, a3, a4):
  3. print("\(a1) , \(a2) , \(a3) , \(a4)")
  4. case let .QRCode(s):
  5. print(s)
  6. }

两个得到相同的结果 : DSLEKWLJELJAIWFLWKJF

  • 给枚举指定特定类型 (原始值)
    你可以给一个枚举指定类型 ,比如说String 类型 。
  1. enum SignBuilding : String{
  2. case Beijing = "天安门"
  3. case XiAn = "兵马俑"
  4. }

这里将 这个枚举定义成 字符串类型的 。
通过这样可以取到对应的值print(SignBuilding.Beijing.rawValue)

也可以原始值隐式赋值

  1. enum IntVal:Int {
  2. case Val1 = 1 , Val2 , Val3
  3. }

如果没给Val1赋值 ,默认是 0 。递增是 1 ,也可以 自己制定初始值 (这里我们给定了初始值1)
也可以使用原始值来初始化枚举 let val = IntVal(rawValue: 2)``print(val) //Optional(IntVal.Val2) ,这里得到的结果是Optional类型 ,因为不是所有的数字都能匹配到对应的枚举类型 。如 :let errorVal = IntVal(rawValue: 5)``print(errorVal) //nil

官方还给出了递归枚举 ,关键字 indirect ,但是我这边尝试了好多次 ,这个关键字也没有变色 ,还会报错 。

  1. enum Calculate{
  2. case Num(Int)
  3. indirect case Plus(Calculate,Calculate)
  4. indirect case ChenFa(Calculate,Calculate)
  5. }

在网上搜了下 , 因为是2.0的新特性 ,网上也没有太多的解释。大家可以研究下 ,我也研究下 ,研究出来再来补上。

枚举里面还可以有方法 ,不过不太推荐把 ,完全可以用结构体和方法 。

枚举和结构体都是值类型 ,在传递的时候都是以拷贝的方式。类是引用类型 ,传递的时候只是传递一个引用 。

2、类和结构体

Class 结构体 struct 简单的定义

  1. struct myPoint
  2. {
  3. var x = 0;
  4. var y = 0;
  5. }
  6. class Person {
  7. var name:String?;
  8. var age:Int?;
  9. var p1 = myPoint(x: 1,y: 2);
  10. var p = myPoint();
  11. }

这里定义了一个简单的结构体和类,类中定义了几个简单的属性 , 包括 一个结构体属性 ,给出了两种初始化的方法 。关于属性的声明可以去看 Swift详解之一 ——– 变量声明 。

Int , float , 数组 字典 等 都是值类型 后台都以结构体的方式实现
一般使用结构体的情况

  1. 结构体的主要目的是用来封装少量 简单的数据值
  2. 预计实例在赋值或传递过程中将会被拷贝 而不是引用
  3. 任何在结构体中存储的值类型属性也将被拷贝 而不是引用
  4. 不需要继承已存在的类型 或者属性 行为(结构体是没有继承的)

如果创建了一个结构体的实例,并且将这个实例赋值给一个常量 则无法修改其属性 ,就算是变量属性也无法修改

  1. let p1 = myPoint(x: 1,y: 1)

这里我尝试修改结构体中的变量x 报错 。

引用类型赋给常量,仍然可以改变其变量属性,所以类的实例可以赋值给一个常量

  • 懒加载

延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用lazy来标示一个延迟存储属性。 (懒加载)

  1. 注意:必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。

看下官方给的例子。

  1. class DataImporter {
  2. /*
  3. DataImporter 是一个将外部文件中的数据导入的类。
  4. 这个类的初始化会消耗不少时间。
  5. */
  6. var fileName = "data.txt"
  7. // 这是提供数据导入功能
  8. }
  1. class DataManager {
  2. lazy var importer = DataImporter() //这里使用了懒加载 在第一次用到的时候才去创建这个实例 如果创建DataManager 就去创建DataImporter 有可能并不需要这个实例,浪费内存和时间
  3. var data = [String]()
  4. // 这是提供数据管理功能
  5. }
  1. let manager = DataManager()
  2. manager.data.append("Some data")
  3. manager.data.append("Some more data")
  4. // DataImporter 实例的 importer 属性还没有被创建

这里可以看到我们并没有使用DataImporter , 所以在创建DataManager()的时候并不并不需要初始化DataImporter ,所以我们使用懒加载在这时候就节省了内存的开支。

但是,如果被标记位lazy的属性 在没有被初始化的时候被多个线程访问 这时候 不能保证这个属性只被实例一次

我们可以通过下面的方式定义一个只读属性 。

  1. var a = 1.2;
  2. var b:Double{
  3. return a*4
  4. }
  • 类型属性
    不管这个类有多少个实例 ,它的类属性 只有一个 。
    关键字 static
  1. struct myStruct
  2. {
  3. static var height = 19.3
  4. }

可以直接通过结构体的名字或者类的名字来调用类型 属性print(myStruct.height)

不过在类中有时候需要使用关键字class ,来允许它的子类重写这个属性 。

  1. class myClass {
  2. static let name = "zhangsan "
  3. static var age = 21
  4. static var status: Int { return 1 }
  5. //在定义计算型属性的时候可以使用 关键字 class 来支持子类对父类进行重写
  6. class var canOverrid: Int { return 10 }
  7. }
  1. class sonClass: myClass {
  2. override static var canOverrid: Int { return 89 }
  3. //static let name = "zhangsan " //cannot override with a stored property 'name'
  4. }

这里我们子类可以重写class 标记的类型属性 。

  • 方法
    方法可以分成实例方法和类型方法 。
    类、结构体、枚举都可以定义实例方法;实例方法为给定类型的实例封装了具体的任务与功能。类、结构体、枚举也可以定义类型方法;类型方法与类型本身相关联。

结构体和枚举可以定义方法 是swift和oc的一大区别

类型方法就是在func 前面加static 类有时候可能需要加class 。跟属性的用法是一样的,这里就不在实例 。

  • 变异方法

值类型的属性不能在实例方法中被修改,但是有时候你确实想修改过,这时候 你可以使用变异方法 。关键字 mutating

  1. struct Counter{
  2. var count = 0
  3. func getCount() ->Int{
  4. return count
  5. }
  6. //因为值类型的属性不能在实例方法中被修改 这里使用了变异方法
  7. mutating func increment()
  8. {
  9. count++
  10. }
  11. }
  12. var c = Counter()
  13. print(c.count) // 0
  14. print(c.getCount()) // 0
  15. c.increment()
  16. print(c.count) // 1

变异方法可以给自己赋值

  1. enum Level {
  2. case High , Mid ,Low
  3. mutating func next() {
  4. switch self
  5. {
  6. case .High:
  7. self = Mid
  8. case .Mid:
  9. self = Low
  10. default:
  11. self = High
  12. }
  13. }
  14. }
  15. var level = Level.High
  16. level.next()
  17. print(level) //Level.Mid
  18. level.next()
  19. print(level) //Level.Low

学习iOS,有他就够了,小码哥视频,传智、黑马、各种swift书籍

相关文章