枚举、结构体、类
注:本文为作者自己总结。过于基础的就不再赘述 ,都是亲自測试的结果。如有错误或者遗漏的地方。欢迎指正,一起学习。
1、枚举
枚举是用来定义一组通用类型的一组相关值 ,关键字enum
,case
关键词表明新的一行成员值将被定义。
enum Direction{
case East
case West
case South
case North
}
这里定义了一个简单的枚举类型 , 里面有四个枚举元素 。
也能够用一行的形式
enum Direction{
case East , West , South , North
}
能够这样来訪问这个枚举类型var dir = Direction.East
。这时候这个变量 dir
已经被判断成Direction
,又一次赋值的时候 能够直接用短语法dir = .West
。
- 相关值(Associated Values)
你能够定义 Swift 的枚举存储不论什么类型的相关值,假设须要的话,每一个成员的数据类型能够是各不同样的。
enum Barcode {
case UPCA(Int , Int , Int ,Int )
case QRCode(String)
}
你能够这样给它赋值var pro = Barcode.UPCA(8, 53627, 29009, 1)
。也能够这样改动pro = .QRCode("DSLEKWLJELJAIWFLWKJF")
这样取值
switch pro{
case .UPCA(let a1,let a2, let a3, let a4):
print("\(a1) , \(a2) , \(a3) , \(a4)")
case .QRCode(let s):
print(s)
}
你也能够把let写在最前面
switch pro{
case let .UPCA( a1, a2, a3, a4):
print("\(a1) , \(a2) , \(a3) , \(a4)")
case let .QRCode(s):
print(s)
}
两个得到同样的结果 : DSLEKWLJELJAIWFLWKJF
- 给枚举指定特定类型 (原始值)
你能够给一个枚举指定类型 。比方说String 类型 。
enum SignBuilding : String{
case Beijing = "天安门"
case XiAn = "兵马俑"
}
这里将 这个枚举定义成 字符串类型的 。
通过这样能够取到相应的值print(SignBuilding.Beijing.rawValue)
也能够原始值隐式赋值
enum IntVal:Int {
case Val1 = 1 , Val2 , Val3
}
假设没给Val1赋值 。默认是 0 。递增是 1 ,也能够 自己制定初始值 (这里我们给定了初始值1)
也能够使用原始值来初始化枚举 let val = IntVal(rawValue: 2)
print(val) //Optional(IntVal.Val2)
,这里得到的结果是Optional类型 ,由于不是全部的数字都能匹配到相应的枚举类型 。如 :let errorVal = IntVal(rawValue: 5)
print(errorVal) //nil
官方还给出了递归枚举 ,关键字 indirect
。可是我这边尝试了好多次 ,这个关键字也没有变色 ,还会报错 。
enum Calculate{
case Num(Int)
indirect case Plus(Calculate,Calculate)
indirect case ChenFa(Calculate,Calculate)
}
在网上搜了下 , 由于是2.0的新特性 。网上也没有太多的解释。大家能够研究下 。我也研究下 ,研究出来再来补上。
枚举里面还能够有方法 ,只是不太推荐把 。全然能够用结构体和方法 。
枚举和结构体都是值类型 。在传递的时候都是以拷贝的方式。
类是引用类型 ,传递的时候仅仅是传递一个引用 。
2、类和结构体
类 Class
结构体 struct
简单的定义
struct myPoint
{
var x = 0;
var y = 0;
}
class Person {
var name:String?;
var age:Int?;
var p1 = myPoint(x: 1,y: 2);
var p = myPoint();
}
这里定义了一个简单的结构体和类,类中定义了几个简单的属性 , 包含 一个结构体属性 ,给出了两种初始化的方法 。关于属性的声明能够去看 Swift具体解释之中的一个 ——– 变量声明 。
Int , float 。 数组 字典 等 都是值类型 后台都以结构体的方式实现
一般使用结构体的情况
- 结构体的主要目的是用来封装少量 简单的数据值
- 估计实例在赋值或传递过程中将会被拷贝 而不是引用
- 不论什么在结构体中存储的值类型属性也将被拷贝 而不是引用
- 不须要继承已存在的类型 或者属性 行为(结构体是没有继承的)
假设创建了一个结构体的实例。而且将这个实例赋值给一个常量 则无法改动其属性 。就算是变量属性也无法改动
let p1 = myPoint(x: 1,y: 1)
这里我尝试改动结构体中的变量x 报错 。
引用类型赋给常量,仍然能够改变其变量属性。所以类的实例能够赋值给一个常量
- 懒载入
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。
在属性声明前使用lazy来标示一个延迟存储属性。 (懒载入)
注意:必须将延迟存储属性声明成变量(使用var关键字),由于属性的值在实例构造完毕之前可能无法得到。而常量属性在构造过程完毕之前必须要有初始值,因此无法声明成延迟属性。
看下官方给的样例。
class DataImporter {
/*
DataImporter 是一个将外部文件里的数据导入的类。
这个类的初始化会消耗不少时间。
*/
var fileName = "data.txt"
// 这是提供数据导入功能
}
class DataManager {
lazy var importer = DataImporter() //这里使用了懒载入 在第一次用到的时候才去创建这个实例 假设创建DataManager 就去创建DataImporter 有可能并不须要这个实例。浪费内存和时间
var data = [String]()
// 这是提供数据管理功能
}
let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// DataImporter 实例的 importer 属性还没有被创建
这里能够看到我们并没有使用DataImporter , 所以在创建DataManager()的时候并不并不须要初始化DataImporter ,所以我们使用懒载入在这时候就节省了内存的开支。
可是。假设被标记位lazy的属性 在没有被初始化的时候被多个线程訪问 这时候 不能保证这个属性仅仅被实例一次
我们能够通过以下的方式定义一个仅仅读属性 。
var a = 1.2;
var b:Double{
return a*4
}
- 类型属性
无论这个类有多少个实例 ,它的类属性 仅仅有一个 。
关键字static
struct myStruct
{
static var height = 19.3
}
能够直接通过结构体的名字或者类的名字来调用类型 属性print(myStruct.height)
只是在类中有时候须要使用关键字class
,来同意它的子类重写这个属性 。
class myClass {
static let name = "zhangsan "
static var age = 21
static var status: Int { return 1 }
//在定义计算型属性的时候能够使用 关键字 class 来支持子类对父类进行重写
class var canOverrid: Int { return 10 }
}
class sonClass: myClass {
override static var canOverrid: Int { return 89 }
//static let name = "zhangsan " //cannot override with a stored property ‘name‘
}
这里我们子类能够重写class
标记的类型属性 。
- 方法
方法能够分成实例方法和类型方法 。
类、结构体、枚举都能够定义实例方法;实例方法为给定类型的实例封装了具体的任务与功能。类、结构体、枚举也能够定义类型方法;类型方法与类型本身相关联。
结构体和枚举能够定义方法 是swift和oc的一大差别
类型方法就是在func 前面加static 类有时候可能须要加class 。
跟属性的使用方法是一样的,这里就不在实例 。
- 变异方法
值类型的属性不能在实例方法中被改动。可是有时候你确实想改动过。这时候 你能够使用变异方法 。
关键字 mutating
struct Counter{
var count = 0
func getCount() ->Int{
return count
}
//由于值类型的属性不能在实例方法中被改动 这里使用了变异方法
mutating func increment()
{
count++
}
}
var c = Counter()
print(c.count) // 0
print(c.getCount()) // 0
c.increment()
print(c.count) // 1
变异方法能够给自己赋值
enum Level {
case High , Mid ,Low
mutating func next() {
switch self
{
case .High:
self = Mid
case .Mid:
self = Low
default:
self = High
}
}
}
var level = Level.High
level.next()
print(level) //Level.Mid
level.next()
print(level) //Level.Low
学习ios。有他就够了,小码哥视频,传智、黑马、各种swift书籍