Swift -- 7.3 类和结构体
swift的类和结构体高度相似,无论是定义语法还是用法上,swift的类和结构体都具有高度的相似性
区别是:结构体不支持继承(自然也不支持类型转换了。。。。。这个,还不太理解)
结构体不支持定义析构器
结构体是值类型,而类是引用类型
苹果的官方文档中说结构体的使用场景不多,主要还是应该使用类
那么哪些场景需要用到结构体呢:
苹果的官方文档表示,当满足以下一个或多个条件时,应该使用结构体
*结构体的主要目的是用于封装少量相关的简单数据值
如果程序需要让该实例在赋值或参数传递时会自动复制副本,则应该使用结构体
如果程序明确该类型无须继承另一个已有的的类或被其他类继承,则可以考虑使用结构体
一个类中包含三种成员:构造器,属性,方法
swift语言通过类名后添加圆括号来表示调用构造器,从而返回该类的实例
如果程序员自己没有写构造器,系统会提供一个默认的无参的构造器,如果自己写了,系统就不提供默认的构造器
class修饰的成员(类成员)不能访问没有class修饰的成员(实例成员)
定义结构体和定义类的主要区别是:结构体不支持继承,因此结构体不能使用final修饰
如果程序员没有为结构体提供构造器,系统则会为该结构体提供两个构造器:一个无参的构造器,一个初始化所有存储属性的构造器
class,static两个修饰符的作用几乎完全相同,只是使用场景不同。定义类时,使用class修饰类中成员,将遮羞成员转成类型相关的成员,没有该修饰符的是实例成员;定义结构体或枚举时,使用static修饰枚举或结构体的成员,将这些成员转成类型相关的成员,没有该修饰符修饰的是实例成员,所以static和class两个修饰符不会同时出现
swift语言要求类中定义的存储属性必须指定初始值,要么在定义时指定初始值,要么在构造器中指定初始值
swift的构造器隐式的将self作为返回值
定义和创建实例
//定义一个person类 class Person { var name : String = "" var age : Int = 0 func say(content:String) { print(content) } } //定义一个dog结构体 struct Dog { var name : String var age : Int func run() { print("\(name) is running") } } //创建实例 var p6:Person p6 = Person() var p5 = Person() var p7 = p6 p6.name = "sun" p6.say("swift is so easy") print(p6.name) print(p5.name) p6.name = "zhu" print(p7.name) var dogfff = Dog(name: "doggy", age: 4) print(dogfff.age) dogfff.run() var dogggg = dogfff dogggg.name = "happy" print(dogfff.name)
使用===和!==来判断引用类型是否指向同一个实例
class User { var name:String var age:Int init(name:String , age:Int) { self.name = name self.age = age } } var u1 = User(name: "abe", age: 12) var u2 = User(name: "abe", age: 12) print(u1 === u2) var u3 = u1 print(u3 === u1) struct Level { var grade:Int } var v1 = Level(grade: 1) var v2 = Level(grade: 2) //print(v1 === v2) 这里不能这样写,因为只有引用类型能这样比较
运算符重载
func == (left:User, right:User) -> Bool { return left.name == right.name && left.age == right.age } func != (left:User, right:User) -> Bool { return !(left == right) } var resultttt = u1==u2 print(resultttt)
存储属性
枚举不能定义实例存储属性,只有类和结构体才能定义实例存储属性;枚举,类,结构体都可以定义类型存储属性
在结构体中,声明的存储属性可以不赋予初始值,因为系统会自动生成一个构造器,用来赋予初始值
struct FixedLengthRange { var start: Int let length: Int } var rg = FixedLengthRange(start: 2, length: 10) rg.start = 5
延迟存储属性
在第一次被调用时才会被计算初始值的属性,声明延迟存储属性需要使用lazy修饰符
延迟存储是一种延迟加载(lazy load)机制,当某个实例持有另一个创建成本较大的实例的引用时,使用延迟存储可以降低内存开销,从而提升程序性能
class Dept { var id : Int var info : String init(id : Int) { self.id = id NSThread.sleepForTimeInterval(2) self.info = "2 second late" } } class User4 { var id:Int = 0 lazy var dept = Dept(id: 20)//dept 属性会在被调用的时候才被初始化,提升了程序的性能 var nicks = [String]() } var usersss = User4() usersss.nicks.append("sun") usersss.nicks.append("qiqiqi") print(usersss.nicks)
计算属性
枚举,结构体,类都可以定义计算属性
enum Seasonnn { case Spring, Summer, Fall, Winter var info:String{ get{ print("the get method is running") switch(self) { case .Spring: return "flower" default: return "no" } } set (newValue){ print("the set method is running and the pragmatic is \(newValue)") } } } var s = Seasonnn.Spring print(s.info) s.info = "baby" //简化的set方法 enum Seasonnn2 { case Spring, Summer, Fall, Winter var info:String{ get{ print("the get method is running") switch(self) { case .Spring: return "flower" default: return "no" } } set{ print("the set method is running and the pragmatic is \(newValue)") } } } /* 声明只读的计算属性 没有set方法,只有get方法 这里可以省略get这个关键字和花括号 */ enum Seasonnn3 { case Spring, Summer, Fall, Winter var info:String{ get{ print("the get method is running") switch(self) { case .Spring: return "flower" default: return "no" } } } } var ss = Seasonnn3.Spring
属性观察者机制
为了让程序能在属性被赋值时获得执行代码的机会,swift提供了属性观察者机制,属性观察者其实就是两个特殊的回调方法
willSet(newValue) 被观察的属性即将被赋值之前自动调用该方法
didSet(oldValue) 被观察的属性被赋值完成之后自动调用该方法
willSet部分可以显式指定
class People { var name:String = "" { willSet{ if(newValue.characters.count > 6) || (newValue.characters.count < 2){ print("the name you input is iligo") } else { print("set name success") } } didSet{ print("set name over") } } } var jane = People() jane.name = "d" print(jane.name)//虽然这两个方法有监察作用,但是并不能阻止赋值的执行