美文网首页
在Swift中使用extension给已有的类添加属性

在Swift中使用extension给已有的类添加属性

作者: 袁方 | 来源:发表于2019-10-18 18:05 被阅读0次

简介

在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等方法中使用点语法调用即可啦.

相关文章

网友评论

      本文标题:在Swift中使用extension给已有的类添加属性

      本文链接:https://www.haomeiwen.com/subject/srlwmctx.html