关联对象Associated Object

在Swift中,可以像Objective-C一样,使用关联对象

为什么扩展不能添加存储属性?

因为,属性涉及到类/结构体的内存结构,所以不能添加属性,但是可以添加计算属性,因为计算属性的本质就是方法

如何给扩展添加计算属性?

类似Objective-C中给分类添加属性,手动实现getter/setter方法

class Student {}
var abc: Int = 22
extension Student {
    var age: Int {
        get {
            // object: Any 关联的是哪一个对象,一般给谁扩展就传哪个对象,因此是self
            // key: UnsafeRawPointer 根据这个地址(当做字典中的key),去关联的对象self中查找value
            objc_getAssociatedObject(self, &abc) as! Int
        }
        set {
            objc_setAssociatedObject(self, &abc, newValue, .OBJC_ASSOCIATION_ASSIGN)
        }
    }
}

var abc = 10

为什么全局变量可以作为key?

因为是全局变量,因此在内存中地址是唯一的,而且整个程序运行中是不变的,因此&abc可以作为key

两个计算属性可以共用一个key吗?

class Student {}
var abc: Int = 22
extension Student {
    var age: Int {
        get {
            objc_getAssociatedObject(self, &abc) as! Int
        }
        set {
            objc_setAssociatedObject(self, &abc, newValue, .OBJC_ASSOCIATION_ASSIGN)
        }
    }
    
    var weight: Int {
        get {
            objc_getAssociatedObject(self, &abc) as! Int
        }
        set {
            objc_setAssociatedObject(self, &abc, newValue, .OBJC_ASSOCIATION_ASSIGN)
        }
    }
}

显而易见,不可以,因为通过&abc这个地址拿到的不能确定是哪个属性

class Student {}
extension Student {
    
    // 本质就是全局变量:1.内存中地址是唯一的 2.程序运行中是不可变的
    // 我们使用的是变量的地址
    // Bool类型就占用1个字节,能省则省,不要用Int(8个字节),String
    private static var AGE_KEY: Bool = false

    // 也是占用1个字节
    private static var WEIGHT_KEY: Void?
    
    var age: Int {
        get {
            objc_getAssociatedObject(self, &Self.AEG_KEY) as! Int
        }
        set { // Self.AEG_KEY == Student.AEG_KEY
            objc_setAssociatedObject(self, &Student.AEG_KEY, newValue, .OBJC_ASSOCIATION_ASSIGN)
        }
    }
}