Swift 属性⑦

2020-08-04  本文已影响0人  Aliv丶Zz

Swift中跟实例相关的属性可以分为2类

实例:

struct Circle {
    //半径  存储属性
    var radius: Double
    //直径  计算属性
    var diameter: Double{
        set{
            radius = newValue / 2
        }
        /* set(aValue){
           radius = aValue / 2
           }*/
        get{
            radius * 2
        }
    }
}

var c = Circle(radius: 10)
print(c.diameter)//20.0
print(MemoryLayout.stride(ofValue: c))
// 8个字节 这里仅存储属性radius占用8个字节。diameter是计算属性,也就是方法,不占用实例对象本身的内存

1. 存储属性

关于存储属性,Swift有个明确的规定:

2. 计算属性

struct Circle {
    //半径  存储属性
    var radius: Double
    //直径  计算属性
    var diameter: Double{
        set(aValue){
           radius = aValue / 2
        }
        get{
            radius * 2
        }
    }
}
struct Circle {
    //半径  存储属性
    var radius: Double
    //直径  计算属性
    var diameter: Double{//只读
        get{
           return radius * 2
        }
    }
}
// 只有get时,也可简写
struct Circle {
    //半径  存储属性
    var radius: Double
    //直径  计算属性
    var diameter: Double {radius * 2}
}

注意:定义计算属性时。必须用var不能用let

let代表的是常量:值是一成不变的
计算属性的值是可能发生变化的。(即使是只读计算属性)
//例如上面diameter虽然是只读的,但是当radius改变时,diameter会随着radius改变而改变


枚举rawValue原理的本质就是:只读计算属性


3. 延迟存储属性

使用lazy 尅定义一个延迟存储属性,在第一次用到属性的时候才会进行初始化

class Car {
    init() {
        print("Car init ")
    }
    func run() {
        print("car is Runnig")
    }
}

class Person {
    lazy var car = Car()
    init() {
        print("Person Init")
    }
    func goOut() {
        car.run()
    }
}

var p = Person()
print("===============")

p.goOut()

Car init
Person Init
===============
car is Runnig

Person Init
===============
Car init
car is Runnig

注意点:

  1. 当结构体包含延迟存储属性时,只有var才可以访问延迟存储属性。( 因为延迟存储属性初始化时要改变结构体内存)
注意点.png

4. 属性观察器

可以为非lazyvar 存储属性设置属性观察器

struct Circle {
    var radius: Double {
        willSet{
            print("willSet:",newValue)
        }
        didSet{
            print("oldValue:",oldValue,"didSet",radius)
        }
    }
    init() {
        self.radius = 1.0
        print("Circle init")
    }
}

var ci = Circle()
ci.radius = 2.0

输出结果:

Circle init
willSet: 2.0
oldValue: 1.0 didSet 2.0
Program ended with exit code: 0

注意点:

  1. willSet会传递新值,默认叫做 newValue
  2. didSet会传递旧值,默认叫做oldValue
  3. 在初始化器中设置属性值,不会触发 wllSetdidSet
  4. 在属性定义时设置初始化值也不会触发wllSetdidSet
  5. 属性观察器、计算属性的功能,同样可以应用在全局变量、局部变量身上

5. inout

func testInout(_ num: inout Int){
    num = 20
}
var age = 18
testInout(&age)
print("age:",age )

结果:

age: 20

实例:

struct Shape {
    var width: Int
    var side: Int{
        willSet{
            print("willSetSide",newValue)
        }
        didSet{
            print("didSetSide",oldValue,side)
        }
    }
    
    var girth: Int {
        set{
            print("setGirth:",newValue)
            width = newValue/side
        }
        get{
            print("getGirth")
            return width * side
        }
    }
    
    func show()  {
        
        print("width = \(width), side = \(side) ,girth = \(girth)")
    }
}
func testInout(_ num: inout Int){
    print("testInout")
    num = 20
}
var sha = Shape(width: 10, side: 4)
print("----- init -----")
testInout(&sha.width)
sha.show()
print("----- -----")

testInout(&sha.side)
sha.show()
print("----- -----")

testInout(&sha.girth)
sha.show()

【打印结果】:

----- init -----
testInout
getGirth
width = 20, side = 4 ,girth = 80


testInout
willSetSide 20
didSetSide 4 20
getGirth
width = 20, side = 20 ,girth = 400


getGirth
testInout
setGirth: 20
getGirth
width = 1, side = 20 ,girth = 20
Program ended with exit code: 0

inout的本质:

  1. 如果实参有物理内存地址,且没有设置属性观察器
  1. 如果实参是计算属性 或者 设置了属性观察器
  • 调用该函数时,先复制实参的值,产生副本【get】
  • 将副本的内存地址传入函数(副本进行引用传递),在函数内部可以修改该副本的值
  • 函数返回后,再将该副本的值覆盖实参的值【set】

总结inout的本质就是引用传递(地址传递)

6. 类型属性

可以通过static定义类型属性;
如果是类,也可以用关键字class定义。
类型属性可以分为:

  1. 存储实例属性:存储在实例的内存中,每个实例都有一份
  2. 计算实例属性:不在实例内存中,其本质是函数
  1. 存储类型属性:整个程序运行过程中,就只有一份内存(类似于全局变量)
  2. 计算类型属性:类似计算属性

实例:

let c1 = Car.init()
let c2 = Car.init()
let c3 = Car.init()
print(Car.count)

【打印结果】:

Car_Count: 3

【类型属性细节】:

使用类型属性可以定义单例
class FileManager {
    public static let share: FileManager = FileManager()
    private init(){
        
    }
}

其他

全局变量在内存中的存储信息
上一篇下一篇

猜你喜欢

热点阅读