主要的不同点有
类有继承的特性,而结构体没有
类型转换使您能够在运行时检查和解释实例的类型
类有析构函数用来释放其分配的资源
引用计数允许对一个类实例有多个引用
在类里面可以通过deinit析构函数把一些对象进行释放掉的。
下面的引用类型,也就意味着一个类类型的变量并不直接存储具体的实例对象,是对当前存储具体实例内存地址的引用。我们通过withUnsafePointer去打印其内存地址,发现to和t1是相邻的,其地址相差8字节的。
swift中有引用类型,就是值类型,最典型的就是struct,结构体的定义也非常简单,相比较类类型的变量中存储的是地址,那么值类型存储的就是具体的实例(或者说具体的值)。
下面代码是用struct去定义的,当把t1=t,打印后其都是值,值相等,如果这个时候改变t1.age=20,只会改变t1不会对t产生影响,因为是值传递。
另外引用类型和值类型还有一个最直观的区别就是存储的位置不同:一般情况值类型存储的在栈上,引用类型存储在堆上。
当我们在结构体里存放个一个实例对象P,age和name存放在栈上的,这个时候的实例对象P也存放在栈上的,P里面存放的内存地址是在堆上开辟的,t这个结构体变量还是存放在堆上的,所以结构体里存放个实例对象是不改变结构体存放的位置的。
通过两个实例来打印struct和class所用的时间,发现struct明显要快。class用了7.5s,而struct只用了5.57s。
类的初始化器
需要注意的一点是:当前的类编译器默认不会自动提供成员初始化器,但是对于结构体来说编译器会提供默认的初始化方法(前提是我们自己没有指定指定初始化值)
下面的是提供默认的值,18,“lg”,这个初始化器就是默认的init(),因为赋值了。
Swift中创建类和结构体的实例时必须为所有的存储属性设置一个合适的初始值。所以类LGPerson必须要提供对应的指定初始化器,同时我们也可以为当前的类提供便捷初始化器(注意:便捷初始化器必须从相同的类里调用另一个初始化器)
下面加了convenience就是便捷的意思,便捷初始化器。没有convenience开头的就是默认初始化器。在convenience中我们需要调用init,这个是为了保持内存安全,进行初始化其值,防止为空。如果把convenience里的self.age和self.name放在self.init前面的话就会报错。
使用初始化器需要注意点:
1)指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成。
2)指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做,指定初始化器赋予的新值将被父类中的初始化器所覆盖。
3)便捷初始化器必须先委托同类中的其它初始化器,然后再为任意属性赋新值(包括同类里定义的属性)。如果没这么做,便捷构初始化器赋予的新值将被自己类中其它指定初始化器所覆盖。
4)初始化器在第一阶段初始化完成之前,不能调用任何实例方法,不能读取任何实例属性的值,也不能引用self作为值。
可失败初始化器
这个也非常好理解,也就意味着当前因为参数的不合法或者外部条件的不满足,存在初始化失败的情况。这种Swift中可失败初始化器写return nil语句,来表明可失败初始化器在何种情况下会触发初始化失败。
必要初始化器
在类的初始化器前添加required修饰符来表明所有该类的子类都必须实现该初始化器
swift中初始化代码分析
我们在苹果的官网下载swift源码,然后定位到HeapObject.cpp里,会发现其底层代码调用的一个逻辑。
swift对象内存分配:
__allocating_init --> swift_allocObject --> _swift_allocObject --> swift_slowAlloc --> Malloc
Swift对象的内存结构HeapObject,有两个属性:一个是Metadata,一个是RefCount,默认占用16字节大小。OC里对象object_objectC里是isa指针等
Swift里类的结构探索
swift里类的内存结构如下: