简介
在Swift中, 正常情况下使用 extension 给已有的类添加属性会报错: "Extensions must not contain stored properties". 大意是说扩展不得包含存储的属性. 其本质原因是extension不会自动生成某个属性的 getter 与 setter 方法. 故无法正常的添加属性并使用. 解决方法则是使用Runtime的关联对象方法来手动为我们添加的属性实现 getter 与 setter 方法, 重要使用到的两个方法是 objc_getAssociatedObject 和 objc_setAssociatedObject .
注: objc_setAssociatedObject 方法的作用是使用关联键和关联策略为关联对象设置关联值. objc_getAssociatedObject 方法则相反, 它会返回与关联键的关联对象所关联的值.
场景
比如我们需要在App端实现一个模拟手势触控板.
仔细分析一下需求, 很容易就想到我们需要处理繁杂的手势操作: 单指点按, 多指点按, 以及各种各样的滑动操作. 势必会在很多时刻需要判断与处理每个UITouch对象的当前状态. 如果引入一个字典来记录其状态, 则整个体系结构既繁杂也不清晰, 代码维护性也较差. 综上, 我们应该采用extension给UITouch类添加touchStatus属性来记录当前状态, 整个结构就一目了然非常清晰, 其状态改变时的操作也不繁琐.
注: UITouch对象的状态有四种: Began(开始), Moved(滑动), Ended(结束), Cancel(取消).
实现:
注: 以下代码需要写入UITouch的扩展(extension)里
/// 定义触摸状态的枚举
public enum TouchStatus {
/// 开始
case Began
/// 滑动
case Moved
/// 结束
case Ended
/// 取消
case Cancel
/// 初始化
case Init
}
/// 触摸状态
var touchStatus: TouchStatus {
set {
// * 参数1: 关联的对象
// * 参数2: 确定键的指针
// * 参数3: 关联值
// * 参数4: 属性关联策略, 此处为retain(为对象获取内存), nonatomic(非原子性)
objc_setAssociatedObject(
self,
&AssociatedKey.touchStatusKey,
newValue,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
if let status = objc_getAssociatedObject(self, &AssociatedKey.touchStatusKey) as? TouchStatus {
// * 当对象有设置的状态值时直接返回
return status
}
// * 当对象没有设置的状态值时返回初始化的值
return .Init
}
}
注: 以下代码需要写入UITouch的扩展(extension)外(同一个.swift文件)
/// 扩展属性关联Key
private struct AssociatedKey {
/// 当前touch状态Key
static var touchStatusKey = "touchStatusKey"
}
之后在 touchesBegan, touchesMoved等方法中使用点语法调用即可啦.
网友评论