swifty进阶:属性

125 阅读3分钟

一.private与fileprivate 修饰的函数,编译器会进行检查如果没有继承,编译器默认就添加final标识

二.存储属性

  • 存储属性作为一个特定类和结构体实例一部分的常量或者变量,存储属性要们是变量存储属性(由var关键字引入)要么是常量存储属性(由let关键字引入)
  • let用来声明常量,常量的值一旦设置好便不能再被修改,var用来声明变量,变量的值可以将来设置不同的值
  • 在sil文件中得到,编译器会对var修饰的变量会生成{get,set}方法,let修饰的变量只会生成{get}方法,找不到set方法,所以用let修饰的变量是不能修改的

三.计算属性

  • 存储的属性是常见的,除了存储属性,类,结构体和枚举也能够定义计算属性,计算属性并不存储值,他们提供getter和setter来修改和获取值,对于存储属性来说可以是常量或变量,但是计算属性必须是变量,与此同时我们书写计算属性时候必须包含类型,因为编译器需要期望返回值是什么
struct squqre{
    var width: Doule
    var height: Double
    //struct是静态派发
    //本质上是方法,但是不存储方法,不占据内存空间
    var area: Doble{
        get{
            return width * height//return 可以省略,编译器能推断出
}
        set{
            //newValue是编译器默认帮忙生成的*
            self.width = newValue
        }
}
private(set) var age:Double//对当前结构体来访问是可行的,外部不能访问
fun test(){
    self.age = 1.0
}
//计算属性的本质就是set和get方法

}

四.属性观察者

  • 属性观察者会观察属性值的变化,一个willSet当属性将要被改变时调用,即使这个值与原有的值相同,而didSet在属性已经改变后调用,它们的语法类似getter和setter
class SubjectName{
//存储属性
var subjectName: String = ""{
        willSet{
            print("subjectName will set value\(newValue)")
        }
        didSet{
            print("subjectName has been changed\(newValue))
        }
    }
}
let s = SubjectName()
s.subjectName = "changeName"
  • 生成sil文件知道,在底层赋值的时候会调用willSet,赋值完成后会调用didSet,但是在第一次初始化的时候是不会调用这两个方法的,在初始化的时候是值的拷贝,当然在初始化过程中也不应该调用willSet和didSet,是不安全的
//在继承当中,
class Teacher{
    var age:Int
    var height:Double
    init(_ age: Int, _ height: Double){
        willSet{
         //2
        }
        didSet{
         //3
        }
    }
}
class Son:Teacher{
    override var age:Int{
        willSet{
         //1
        }
        didSet{
         //4
        }
    }
    init(){
        super.init(18,19)
        //初始化已经完成
        self.age = 20
    }
}
//调用顺序如上1->2->3->4

五.类型属性

class Subject{
    //全局静态变量只会被初始化一次,底层是用的dispatch_once_t
    static var age: Int = 18
}
class Subject{
    //单利的创建
    static let shareInstance = Subject()
    private init(){}
}
class Subject{
    //单利的创建
    static fun test(){
      let x = 20
      let y = 30
      var tmp = x + y
      print(tmp)
    }
    //在这个静态函调用过程中就不会涉及到函数派发
}

六.属性在mahco文件的位置信息

struct Metadata{
    var kind:Int
    var superClass:any.Type
    var cacheData:(Int,Int)
    ...
    var typeDescriptor:UnsafeMutableRawPointer
    var iVarDestroyer:UnsafeRawPoniter
    ...
}

在函数调度过程中,我们知道了我们的函数表存储在typeDescriptor
struct TargetClassDescriptor{
    ...
    var fieldDescriptor:Int32//存储的属性
    ...
}

struct FieldDescriptor{
    MangledTypeName int32
    Superclass int32
    ...
    NumFields uint32//代表有多少个属性
    FieldRecords [FieldRecord]//记录相关的属性
}

struct FieldRecord{

    Flags uint32

    MangledTypeName int32

    fieldName int32//属性名称

}
通过macho-view可以通过相关偏移查到属性的值