类(Class)和结构体(Struct)有什么区别
在swift中,class是引用类型.struct是值类型.值类型在传递和赋值的时候将进行复制,而引用类型则只会使用引用对象的一个"指向",所以两者之间的区别就是这两个类型的区别.
class Temperature {
var value : Float = 37.0
}
class Person {
var temp : Temperature?
func sick() {
temp?.value = 41.0
}
}
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
let A = Person()
let B = Person()
let temp = Temperature()
A.temp = temp;
B.temp = temp;
A.sick()
}
由于Tempperature是class,为引用类型,所以A的temp和B的temp指向的同一个对象,A的temp值被修改了,B的temp值也随之被修改.这样A和B的temp值都被修改成了41.0. 如果将Temperature修改成为struct类型.就变成了值类型.则A的temp值修改不会影响B的temp值.
在内存中, 引用类型,诸如类,是在堆上进行存储和操作的,而值类型,比如结构体,是在栈内存上进行存储和操作的,相比栈上的操作, 堆上的操作更加复杂和耗时,所以苹果公司推荐使用结构体,这样可以提高App的运行效率.
**clss的以下功能是struct没有的. **
- 可以继承,这样子类就可以使用父类的特性和方法
- 类型转换可以在运行时检查和解释一个实例类型.
- 可以用deinit来释放资源
- 一个类可以被多次引用.
Struct也有以下的优势.- 结构比较小,适合复制操作,相比一个class的实例被多次引用的话,struct可以更加的安全.
- 无需担心内存泄露或者多线程冲突问题.
Swift是面向对象的还是函数式的编程语言
抛出结论,Swift既是面向对象的编程语言,也是函数式的编程语言
- Swift支持类的封装. 继承和多态,所以Swift是面向对象的编程语言.
- Swift支持Map,reduce,filter.flatmap这类去除中间状态,数学函数式的方法,更加强调运算结果,而不是运算过程. 所以Swift又是函数式的编程语言.
map: Array类的一个方法,可用它对每个数组进行转换
reduce:把数组元素组合计算成一个值
filter:选择数组元素中满足某个条件的值.
Swift中,什么叫可选型(Optional)
在swift中,可选型是为了表达当一个变量值为空的情况,当一个变量值为空的时候, 他就是nil,在Swift中,无论变量是引用类型还是值类型,都可以是可选型变量,
在OC中没有明确提出可选型的概念,但是它的应用类型却可以为nil,用这个来标志其变量值为空的情况,而Swift将这个理念扩大到值类型,并且明确提出了可选型的概念.
Swift中的泛型
在Swift中,泛型主要是为了增加代码的灵活性而增加的. 他可以使对应的代码满足任意类型的变量或方法.
Swift是类型安全的语言,所以交换变量的 变量类型必须一致.
Open, Public, Internal, File-private 和Prvate
Swift有五个级别的访问权限.从高到底依次是Open. Public, Internal,File-private, Private.
他们遵循的基本原则是, 高级别的变量不允许被定义为低级别变量的成员变量.比如,一个Private的class中不能含有Public的string值. 反之, 低级别的变量却可以定义在高级别的变量中,比如Public的class中可以含有Private的Int值.
- Open 是具备有最高的权限,这个修饰符修饰的类和方法可以在任意的Module中被访问和重写. 不过这个修饰符是Swift才增加的一个全新的修饰符.
- Public 的权限仅次于Open,它与Open唯一的区别在于,它修饰的对象可以在任意的Module中被访问. 但是不可以重写
- Internal是默认的权限,他表示只能在当前定义的Module中访问和重写,他可以被一个Module中的多个文件访问,但是不可以被其他Module访问.
- File-private 也是Swift新增加的. 这个修饰的权限只能在当前文件中使用,例如, 他可以被一个文件中的class, extension 和struct共同使用.
- Private 是最低姐别的访问权限,他的对象只能在定义的作用域内使用, 离开了这个作用域,即使同一个文件中的其他作用域,也无法访问.
关键字 Strong weak 和Unowned
Swift的内存管理机制和OC是一样的. 都是ARC.基本原理就是**一个对象在没有任何强引用指向他的时候,所占有的内存就会被回收,反之, 只要有一个强引用指向该对象,他就会一直存在于内存中.
- Strong代表强引用, 是默认的属性.当一个对象被声明为Strong的时候. 表示父层级对该对象有一个强引用的指向. 此时,该对象的引用计数会加1.
- Weak代表弱引用,当一个对象被声明为Weak的时候,表示父层级对该对象没有指向,该对象的引用计数不会+1,在该对象被释放后,弱引用也随之消失,继续访问该对象地址,程序会得到nil,但是不会崩溃.
- Unowned和弱引用的本质一样.唯一不同的是, 对象被释放的时候, 还是会有一个无效的引用指向对象. 他不是Optional,也不指向nil.如果继续访问该对象. 则程序会崩溃.
引入Weak和Unowned是为了解决由Strong带来的循环引用的问题,简单的说,当两个对象互相有一个强指针指向对方的时候就会形成循环引用,导致两个对象在内存中无法被释放.
- 当访问对象可能已经被释放的时候, 使用weak. 比如delegate的修饰
- 当访问的对象不可能被释放的时候, 使用Unowned,比如self的引用.
- 实际上. 很多公司为了安全.强制规定任何时候都使用Weak修饰.
Swift中 copy-on-write
在值类型(比如struct)在复制时,复制的对象和原对象实际上在内存上指向同一个对象. 当且仅当修改复制后的对象时,才会在内存中重新创建一个新的对象.
let arrayA = [1,2,3]
let arrayB = arrayA
arrayB.append(4)
复制的数组和原数组共享同一个地址,直到其中一个发生改变,这样的设计使得值类型可以被多次复制而无需消耗多余的内存,只有变化的时候才会增加开销,因此内存的使用更加的高效.
什么是属性观察
属性观察是指在当前类型内对特定属性进行监视,并且做出响应的行为,属性观察是Swift的特性.具体有两种, 一个willSet和didSet.
var title : String{
willSet{
print()
}
didSet{
print()
}
}
上面对title进行了监听,在title发生改变前,willset对应的作用域将会被执行.
在结构体中如何修改成员变量的方法
protocol Pet{
var name : String { get set}
}
struct MyDog : Pet{
var name: String
func changeName(name:String){
self.name = name
}
}
以上的代码有一点点问题. 应该在方法changeName前面加上关键字 mutating,表示该方法会修改结构体中自己的成员变量.
在设计协议的时候, 由于protocol可以被class和struct或者enum实现, 所以要考虑是否用mutating来修饰方法.
类是不存在以上的问题的, 因为类可以随时修改自己的成员变量.