swift学习第4天

类与结构体

结构体

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
相关推荐
晚枫歌F1 天前
Dpdk介绍
linux·服务器
想进部的张同学1 天前
hilinux-3599---设备学习---以及部署yolo
学习·yolo·海思
风送雨1 天前
FastMCP 2.0 服务端开发教学文档(下)
服务器·前端·网络·人工智能·python·ai
HyperAI超神经1 天前
【vLLM 学习】Rlhf
人工智能·深度学习·学习·机器学习·vllm
model20051 天前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
yuhaiqun19891 天前
学服务器训练AI模型:5步路径助力高效入门
运维·服务器·人工智能·笔记·机器学习·ai
阿杰 AJie1 天前
主流传输 /通信协议的【使用场景 + 详细使用说明】大全
服务器·tcp/ip
工程师老罗1 天前
龙芯2k0300 PMON取消Linux自启动
linux·运维·服务器
skywalk81631 天前
网站证书自动续订失败的问题解决,原来是续订指令certbot renew出错,导致crontab定时任务续订失败
运维·服务器·证书·certbot