一 @mutating 修饰在方法前 修改本属性的值
swift的两种类型:值类型 和 引用类型
值类型
对于值类型,即结构体和枚举,其并不能直接在实例方法中修改实例属性的值,Swift中提供了另一种方式,如果真有如此的需求,开发者可以使用mutating关键字将实例方法声明成可变的,实际上,如果在可变的实例方法中修改了值类型属性的值,是会创建一个新的实例来代替原来的实例的,示例如下:
struct Point {
var x:Double
var y:Double
// 此处修改了属性的值
mutating func move(x:Double,y:Double) {
self.x+=x
self.y+=y
}
}
var point = Point(x: 1, y: 1)
print(point)
point.move(3, y: 3)
print(point)
在值类型实例的可变方法中修改属性的值,实际上就是创建了一个新的实例,上面的写法和下面的写法原理是一样的:
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)
}
}
传递的是参数的一个副本,这样在调用参数的过程中不会影响原始数据。
类与结构体的区别
当开发者在代码中传递这些实例时,结构体总是被复制,而类则是被引用。这是结构体和类的最本质区别。类通过引用计数允许一个类实例的多处引用
引用类型
把参数本身引用(内存地址)传递过去,在调用的过程会影响原始数据,
swift中 class是引用类型,其它的Int、 Float、 Bool、 Character、 Array、 Set、 enum、 struct全都是值类型
二 @inout 让值类型以引用方式传递 即:声明函数时,在参数前面用inout修饰,函数内部实现改变外部参数
swift 3.0 inout 放在参数类型前修饰 eg. fir: inout Int
有时候我们需要通过一个函数改变函数外面变量的值(将一个值类型参数以引用方式传递),这时,Swift提供的inout关键字就可以实现。
var value = 50
print(value) // 此时value值为50
func increment(value: inout Int, length: Int = 10) {
value += length
}
increment(&value)
print(value) // 此时value值为60,成功改变了函数外部变量value的值
注意
inout修饰的参数是不能有默认值的(例子中length = 10被赋予默认值),有范围的参数集合也不能被修饰;
一个参数一旦被inout修饰,就不能再被var和let修饰了。
三 final 防止类被继承
Swift中的final修饰符可以防止类(class)被继承,还可以防止子类重写父类的属性、方法以及下标。需要注意的是,final修饰符只能用于类,不能修饰结构体(struct)和枚举(enum),因为结构体和枚举只能遵循协议(protocol). 虽然协议也可以遵循其他协议,但是它并不能重写遵循的协议的任何成员,这就是结构体和枚举不需要final修饰的原因。
class Shape {
final var center:(Double,Double)
init(){
center = (0,0)
}
}
四 override 子类重写父类方法
默认子类也会继承父类的构造方法,如果子类需要实现自己的构造方法,可以对父类的方法进行覆写,使用override关键字
class Rect: Shape {
var size:(Double,Double)=(0,0)
override init(){
super.init()
super.center = (1,1)
}
}
通过super关键字可以调用父类的属性和方法,同样,也可以使用override关键字来对属性进行get和set的覆写。同样也可以重写属性的观察期willset和didset
五 unowned 无主引用
某个类必须保有另一个类的示例,这个实例不能为nil,但是这个属性又不能影响其原始实例的释放,这种情况也会造成循环引用,示例如下:
class MyClassFive{
unowned var cls:MyClassSix
init(param:MyClassSix){
cls = param
}
deinit{
print("ClassFive deinit")
}
}
class MyClassSix{
var cls:MyClassFive?
deinit{
print("ClassSix deinit")
}
}
var obj6:MyClassSix? = MyClassSix()
var obj5:MyClassFive? = MyClassFive(param: obj6!)
obj6?.cls = obj5
obj5=nil
obj6=nil
关于弱引用和无主引用,其区别主要是在于:
- 弱引用用于解决Optional值的引起的循环引用。
- 无主引用用于解决非Optional值引起的循环引用。
- 个人以为,弱引用可用下图表示:
- 无主引用可用如下图表示:
若将上面的代码修改如下,程序会直接崩溃:
class MyClassFive{
unowned var cls:MyClassSix
init(param:MyClassSix){
cls = param
}
deinit{
print("ClassFive deinit")
}
}
class MyClassSix{
var cls:MyClassFive?
deinit{
print("ClassSix deinit")
}
}
var obj6:MyClassSix? = MyClassSix()
var obj5:MyClassFive? = MyClassFive(param: obj6!)
obj6?.cls = obj5
obj6=nil
obj5?.cls
两类实例引用的属性都为非Optional值的时候,可以使用无主引用与隐式拆包结合的方式来解决,这也是无主引用最大的应用之处,示例如下:
class MyClassSeven{
unowned var cls:MyClassEight
init(param:MyClassEight){
cls = param
}
deinit{
print("ClassSeven deinit")
}
}
class MyClassEight{
var cls:MyClassSeven!
init(){
cls = MyClassSeven(param:self)
}
deinit{
print("ClassEight deinit")
}
}
var obj7:MyClassEight? = MyClassEight()
obj7=nil
除了在两个类实例间会产生循环引用,在闭包中,也可能出现循环引用,当某个类中包含一个闭包属性,同时这个闭包属性中又使用了类实例,则会产生循环引用,示例如下:
class MyClassNine {
var name:String = "HS"
lazy var closure:()->Void = {
//闭包中使用引用值会使引用+1
print(self.name)
}
deinit{
print("ClassNine deinit")
}
}
var obj9:MyClassNine? = MyClassNine()
obj9?.closure()
obj9=nil
//不会打印析构信息
Swift中提供了闭包的捕获列表来对引用类型进行弱引用或者无主引用的转换:
class MyClassNine {
var name:String = "HS"
lazy var closure:()->Void = {
[unowned self]()->Void in
print(self.name)
}
deinit{
print("ClassNine deinit")
}
}
var obj9:MyClassNine? = MyClassNine()
obj9?.closure()
obj9=nil
捕获列表以中括号标识,多个捕获参数则使用逗号分隔。
swift中常用关键字
- 用作声明的关键字:
class
、deinit
、enum
、extension
、func
、import
、init
、let
、protocol
、static
、struct
、subscript
、typealias
、var
- 用作语句的关键字
break
、case
、continue
、default
、do
、else
、fallthrough
、if
、in
、for
、return
、switch
、where
、while
- 用作表达和类型的关键字:
as
、dynamicType
、new
、is
、super
、self
、Self
、Type
、__COLUMN__
、__FILE__
、__FUNCTION__
、__LINE__
- 特定上下文中被保留的关键字:
associativity
、didset
、get
、infix
、inout
、left
、mutating
、none
、nonmutating
、operator
、override
、postfix
、unowned(sale)
、unowned(unsafe)
、weak
、willset