Swift学习

Swift 结构体和类的区别

2021-02-25  本文已影响0人  写代码的小农民

Struct 和Class的区别

不同点#####相同点

1.结构体属于值类型,类属于引用类型;
2.值类型赋值给let var 或者函数传参的时候完,全是深拷贝;
3.引用类型赋值给let var 或者函数传参的时候完,是将内存地址拷贝一份,属于浅拷贝;
4.结构体属于值类型,标准库中的结构体采用copy on write策略,优化效率;
5.结构体不可以继承,可以继承;
6.都可以实现方法,都可以添加计算属性和存储属性,都支持属性监听,都支持扩展.都可以遵守协议.结构体的方法修改属性的时候需要用@mutating修饰(枚举也需要);
7.结构体初始化的时候必须要给属性赋值,来决定结构体在内存中的布局.Class初始化的时候可以暂时不用赋值;
8.结构体声明属性的时候不需要赋值,class 声明属性的时候必须赋值或者包装成Optional;
9.required关键字只支持Class, Class可以用static和Class 关键字修饰静态方法;Struct 只能用Static 修饰;

Class的初始化

初始化required修饰的指定初始化器,子类必须要实现同样的指定初始化器,要么继承要么在子中用required重写父类的指定初始化器;
init?可失败初始化器;
指定初始化器;
可选初始化器;

属性观察期

willset\didset

2,类一定是分配在堆空间上,结构体可能分配在堆空间:比如类中的结构体属性,栈空间:比如声明在方法中,数据段:声明为全局变量

3.存储类型和计算类型

都属于实例属性:只能通过实力去访问
lazy var 是一种延迟的存储类型.存储属性存储在对象或者结构体的内存中,计算属性不占用结构体或者对象的属性.

3.1类型属性 添加static/class修饰

整个程序运行期,只有一份比如单例;
存储类型属性:
计算类型属性:

4.属性观察期

非lazy的var的存储属性,计算属性不能设置属性观察器;但是在初始化的时候设置不会触发(包括在init和定义的时候赋值)

5.计算属性和观察期同样适用与局部变量和全局变量

6.inout

传入存储属性:传入结构体或者对象的地址,然后找到存储属性的值,直接访问或者修改;
传入添加了属性观察器的存储属性:传入结构体或者对象的地址,然后在函数内部开辟一段局部变量作为临时存储,并把这个临时地址传入set方法内重新设置,在此之前会调用willset方法,设置完调用didiset方法;
传入计算属性:传入结构体或者对象的地址,然后先调用计算属性的get方法,然后在函数内部开辟一段局部变量作为临时存储,并把这个临时地址传入set方法内重新设置.

7.方法

类方法和实例方法 也是通过static修饰来区别.用法和OC以一样

7.mutating 用于结构体和枚举这种值类型,在自身的实例方法中修改自身属性

struct Person {
    var x = 1
    mutating func add(num:Int){
        x += num
    }
}
var p = Person()
p.add(num: 1)
enum Dog{
    case big, small
    mutating func change() {
        switch self {
        case .big:
            self = .small
        case .small:
            self = .big
        }
    }
}
var dog = Dog.big
dog.change()
print(dog)

7.@discardableResult用于消除返回函数未使用的警告

8.下标函数

使用subscript可以给任何类型(枚举、结构体、类)增加下标功能;subscript的语法类似于实例方法,计算属性,本质就是方法(函数);
不同点在于结构体中的subscript必须实现set方法才能通过p[0] = 10修改值,但是Class的只需要实现get方法就可以实现p[0] = 10赋值,原因是前者是值拷贝,后者是引用拷贝.

struct Person {
    var x = 1, y = 1
    subscript(index:Int) -> Int{
        set {
            if index == 0 {
               x = newValue
            } else {
                y = newValue
            }
        }
        
        get {
            index == 0 ? x : y
        }
    }
}

var p = Person()
p[0] = 10
p[0]

9.继承

值类型不支持继承,只有类支持继承;
swift不像OC任何类都要继承自某一个类;
重写方法重写下标:calss 修饰的类型方法可以通过override重写,但是static修饰的则不可被重写
重写实例属性:可以把父类的存储属性重写为计算属性,只能重写var属性,重写之后权限大于等于夫类
重写类型属性::calss 修饰的计算属性可以通过override重写,但是static修饰的则不可被重写. 存储属性不可以被calass修饰
属性观察期:可以在子类中为计算属性和存储属性添加属性观察,
不希望继承重写用final修饰
9.1内存结构
前八个字节存放类的基本信息,通过八个字节指向堆空间的一段内存,可以找到方法实现。接下来的八个字节存放类的引用计数。再往后是类的属性的内存地址。

9.多态

OC:runtime
swift:通过前八个字节去查找堆上方法的实现

10.协议、元类型

Self.Type/Perosn.self是类的原类其实就是类的对象的前八个字节的内容,通过元类型可以动态创建类的实例;
协议:可以被类、枚举、结构体遵守;可以继承,可以添加属性和方法,可以定义初始化器,协议约定的方法属性必须要实现,协议可以通过 & 组合作为参数的约束条件,类似于 ;
Any\Anyobject\Anyclass:任意类型,任意对象,任意元类对象

11.Error

12.关联类型

13.some

上一篇下一篇

猜你喜欢

热点阅读