类与结构体
结构体
swift中的结构体,既可以定义属性,又可以定义方法,类似于oc中的类了;
创建完结构体后,结构体会默认生成一个构造方法供开发者使用
swift
struct Car {
var price : Int
var brand : String
var petrol : Int
mutating func drive () {
if petrol > 0 {
petrol -= 1
print("drive 10 milo")
}
}
mutating func addPetrol () {
petrol += 10
print("加了10单位油")
}
}
var car = Car (price: 100000, brand: "奔驰", petrol: 10)
print(car)
for _ in 0...100 {
if (car.petrol == 0) {
car.addPetrol()
} else {
car.drive()
}
}
- 结构体,枚举以及前面读者接触到的除类以外的所有数据类型都属于值类型,只有类是引用类型的
- 当进行数据传递时,值类型总是会被复制一份,引用类型不会;
- 引用类型是通过引用计数来管理生命周期的
swift
struct Car {
var price : Int
var brand : String
var petrol : Int
mutating func drive () {
if petrol > 0 {
petrol -= 1
print("drive 10 milo")
}
}
mutating func addPetrol () {
petrol += 10
print("加了10单位油")
}
}
var car = Car (price: 100000, brand: "奔驰", petrol: 10)
//for _ in 0...100 {
// if (car.petrol == 0) {
// car.addPetrol()
// } else {
// car.drive()
// }
//}
var car02 = car
car02.price = 21314
car02.petrol = 32
print(car)
print(car02)
类
- 类和结构的声明和使用方式基本一致;
- 类需要手动去定义构造方法
- 类是引用类的,所以在数据传递时不会创建新的类对象
swift
class Classcar {
var price : Int
var brand : String
var petrol : Int
func drive () {
if petrol > 0 {
petrol -= 1
print("drive 10 milo")
}
}
func addPetrol () {
petrol += 10
print("加了10单位油")
}
init(price: Int, brand: String, petrol: Int) {
self.price = price
self.brand = brand
self.petrol = petrol
}
}
var classcar = Classcar(price: 100000, brand: "奔驰", petrol: 10)
var classcar02 = classcar
classcar02.price = 21314
classcar02.petrol = 32
print(classcar.price,classcar.brand,classcar.petrol)
print(classcar02.price,classcar02.brand,classcar02.petrol)
设计一个交通工具类
- 继承是类独有的特点:
子类会继承父类的属性和方法,子类也可以去定义自己的属性 和方法,也可以对父类的方法进行覆写 - 覆写的关键字为override
swift
class Transportation {
var petrol : Int = 10
func drive () {
if petrol == 0 {
self.addPetrol ()
}
}
func addPetrol () {
petrol += 10
}
}
class Car : Transportation {
var tyre : Int
override func drive() {
super.drive()
print("drive 10 milo")
petrol -= 1
}
init(tyre: Int) {
self.tyre = tyre
}
}
class Boat : Transportation {
var floor : Int
override func drive() {
super.drive()
print("drive 10 milo in sea")
petrol -= 2
}
init(floor: Int) {
self.floor = floor
}
}
var car = Car(tyre: 4)
var boat = Boat(floor: 2)
car.drive()
boat.drive()
- 子类可以重写父类的属性和方法(但属性好像只能重写计算属性(看着像闭包),不能重写存储属性)
- 如果不希望子类去修改某个类或属性,可以使用final关键字修饰
开发中类与结构体的应用场景
-
要描述的数据类型中只有少量的简单数据类型的属性
-
要描述的数据类型在传递数据时需要以复制的形式进行
-
要描述的数据类型中的所有属性在进行传递时需要以复制的方式进行
-
不需要继承另一个数据类型
满足以上几种情形才使用结构体,否则还是使用类
-
对值类型进行等于比较时,要用"=="
-
对引用类型进行等于比较时,要用 "==="
与oc区别很大的一点:
- 在swift中,Array,Set,Dictionary,String这些数据类型都是采用结构体来实现的,因此在swift中这些数据在传递的时候总是会被复制 ;但也不用担心性能,swift在幕后保证了只有在绝对需要时才会进行真正的复制操作
属性和方法
存储属性
- 存储属性就是用变量或者常量存储的某些有意义的值
- 一般构造方法要保证所有属性都已经被赋值,但如果属性在定义时就已经设置初始值,那么在构造方法中就可以不赋值了
swift
class Student {
var name : String
var age : Int
let sex : String
var schoolName : String = "清华大学"
init(name: String, age: Int, sex: String) {
self.name = name
self.age = age
self.sex = sex
}
}
需要注意的是,变量类型的属性可以修改,常量类型的属性不能修改
如果值类型的实例以常量形式接受,那么它的属性都不能修改
如果引用类型的实例以常量形式接受,那么它的变量类型的属性仍可以修改
swift
struct Point {
var x : Double
var y : Double
}
class PointC {
var x : Double
var y : Double
init(x: Double, y: Double) {
self.x = x
self.y = y
}
}
//let point = Point(x: 2, y: 1)
//point.x = 3
let point2 = PointC(x: 2, y: 2)
point2.y = 5
- swift语言支持将存储属性设置为延时存储属性,也就是只有在调用类实例的这个属性时才会对这个属性初始话赋值,可以大大减少类实例的构造时间
swift
class Work {
var name : String
init(name: String) {
self.name = name
print("完成了Work类实例的创建")
}
}
class People {
var age : Int
lazy var work: Work = Work(name: "jack")
init(age: Int) {
self.age = age
}
}
var people = People(age: 20)
print(people)
print(people.work)
延时存储属性不是线程安全的
计算属性
用来描述可以由其他属性通过计算得到的属性
swift
class Circle {
var r : Double
var center :(Double, Double)
var l : Double {
get {
return 2 * r * Double.pi
}
set {
r = newValue / 2 / Double.pi
}
}
var s : Double {
get {
return Double.pi * r * r
}
set {
r = sqrt(newValue / Double.pi)
}
}
init(r: Double, center: (Double, Double)) {
self.r = r
self.center = center
}
}
var circle = Circle(r: 2, center: (0, 0))
print(circle.l, circle.s)
circle.l = 12 * Double.pi
print(circle.r)
circle.s = 25 * Double.pi
print(circle.r)
- 在set方法中,外界设置的值会以newvalue的形式传入
- get方法必须实现,set方法可选;如果只有get方法,那么这个属性时只读的
属性监听器
swift为存储属性提供了属性监听器
- 在属性初始话或构造的时候,也就是属性第一次赋值的时候不会触发属性监听器的方法,第二次赋值才会
- 属性监听器方法里的传入参数名可以自定义
swift
class Teacher {
var name : String {
willSet {
print("将要设置name为\(newValue)")
}
didSet {
print("已经设置name为\(oldValue)")
}
}
var age : Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
var teacher = Teacher(name: "jack", age: 20)
teacher.name = "Tom"
- 只有存储属性可以设置属性监听器,计算属性不可以
属性包装器
使用属性包装器可以实现计算属性计算过程的复用
-
每个被包装的属性,编译器都会单独生成一个对应的存储属性(名字内部唯一,例如 _memberAge、_memberName)。
这些生成的存储属性直接放在类实例内存里,跟普通属性一样跟随实例生命周期。
-
也就是说属性包装器实例本身就是一个存储属性,然后对外公开为计算属性,外面设值后,内部计算后设置为真正存储的值
swift
@propertyWrapper
struct MoreThanZero {
private var number : Int
init () {
self.number = 0
}
var wrappedValue : Int {
get {
return self.number
}
set {
if (newValue < 0) {
self.number = 0
} else {
self.number = newValue
}
}
}
}
@propertyWrapper
struct NotEmpty {
private var string : String
init () {
self.string = "default"
}
var wrappedValue : String {
get {
return self.string
}
set {
if newValue.count == 0 {
self.string = "default"
} else {
self.string = newValue
}
}
}
}
class Member : CustomStringConvertible {
@NotEmpty var memberName : String
@MoreThanZero var memberAge : Int
var description: String {
return "name: \(self.memberName), age: \(self.memberAge)"
}
}
let member01 = Member()
member01.memberAge = -1
member01.memberName = ""
print(member01)
实例属性和类属性
swift中的类方法是使用static或class声明的
如果需要在子类中重写该属性时,要用class声明
swift
class SomeClass {
static let className = "SomeClass"
static var subName : String {
return "sub" + className
}
class var classSubName :String {
return "sub" + className
}
}
SomeClass.className
SomeClass.subName
SomeClass.classSubName
class subClass : SomeClass {
override class var classSubName: String {
return "newName"
}
}
subClass.classSubName
实例方法和类方法
实例方法的意义与应用
swift
class Math {
func add (param01 : Double,param02 : Double) -> Double {
return param01 + param02
}
func sqr (param01 : Double, param02 : Double) -> Double {
return self.add(param01: param01, param02: param02) * self.add(param01: param01, param02: param02)
}
}
var obj = Math()
obj.sqr(param01: 1, param02: 2) ;
- 对于引用类型,在实例方法中对实例属性进行修改时没有问题
- 对于值类型,使用mutating修饰的实例方法才能对属性进行修改
类方法
swift中的类方法也是通过static和class关键字声明的,同样,static声明的类方法不能被子类重写,class可以
swift
struct Point {
var x : Double
var y : Double
mutating func move (x: Double, y : Double) {
self = Point(x: self.x + x, y: self.y + y)
}
static let name = "Point"
static func printName () {
print(self.name)
}
}
Point.printName()
class MyClass {
class func myFunc () {
print("MyClass")
}
}
class SubMyClass : MyClass {
override class func myFunc() {
print("SubMyClass")
}
}
SubMyClass.myFunc()
下标方法
swift
class MyArray {
var array : Array<Int>
init(array: Array<Int>) {
self.array = array
}
subscript (index: Int) -> Int {
set {
array[index] = newValue
}
get {
return array[index]
}
}
}
var myArray = MyArray(array: [1,2,3,4,5])
myArray[2]
myArray[1] = 0