美文网首页ios专题征服SwiftiOS杂文
Swift3.x 继续 Method Swizzling

Swift3.x 继续 Method Swizzling

作者: 知忧丶 | 来源:发表于2017-06-05 16:30 被阅读1615次

    前言

    • Method 'load()' defines Objective-C class method 'load', which is not permitted by Swift
    • Method 'initialize()' defines Objective-C class method 'initialize', which is not guaranteed to be invoked by Swift and will be disallowed in future versions
      Swift已经彻底丢弃了load方法,最近Swift3.x版本推出后大家发现initialize方法在将来的版本中可能被弃用,那么我们还怎样继续Method Swizzling黑魔法?

    国外大牛提供了优雅的解决方案

    解决思路:initialize()无非就是提供一个入口允许我们将runtime代码插入到适当的位置,那么这个入口是每一个Class必须实现且一定会执行的方法,那么这个就和代理模式很接近了。那么我们可以在程序刚启动时使用runtime获取所有的Class,然后对他们遍历,如果他是Protaocl的代理就立即执行代理方法,我们只需要在代理方法中实现initialize()中要实现的代码。

    • Step One
    /// 定义 `protocol`
    public protocol SelfAware: class {
        static func awake()
    }
    
    // 创建代理执行单例
    class NothingToSeeHere{
    
        static func harmlessFunction(){
            let typeCount = Int(objc_getClassList(nil, 0))
            let  types = UnsafeMutablePointer<AnyClass?>.allocate(capacity: typeCount)
            let autoreleaseintTypes = AutoreleasingUnsafeMutablePointer<AnyClass?>(types)
            objc_getClassList(autoreleaseintTypes, Int32(typeCount)) //获取所有的类
            for index in 0 ..< typeCount{
                (types[index] as? SelfAware.Type)?.awake() //如果该类实现了SelfAware协议,那么调用awake方法
            }
            types.deallocate(capacity: typeCount)
        }
    }
    
    
    • Step Two
    /// 执行单例
    extension UIApplication {
        private static let runOnce:Void = {
            //使用静态属性以保证只调用一次(该属性是个方法)
            NothingToSeeHere.harmlessFunction()
            UIButton.harmlessFunction()
        }()
        
        open override var next: UIResponder?{
            UIApplication.runOnce
            return super.next
        }
    }
    
    • Step Three
    /// 将类设置为代理并在代理中实现运行时代吗
    extension UIButton:SelfAware{
        public static func awake() {
            let instance = UIButton.appearance()
            instance.setTitleColor(UIColor.red, for: .normal)
            instance.backgroundColor = UIColor.green
            instance.titleLabel?.font = UIFont.boldSystemFont(ofSize: 15)
            
        }
    

    后记&&体悟

    虽然Swift弃用了loadinitialize()方法,但我个人认为现阶段影响不是特别大,从Swift角度来看我们要使用runtime的代码大多是和UIKit相关的,而UIKit又是由Objective-C编写的,事实上使用Objective-C来实现是最好的方法,强行使用Swift岂不是缘木求鱼吗?Swift将绝大多数Foundation框架下的许多类改写成了struct,runtime使用的也是比较少的,退一步讲大不了使用Objective-C完成Swift相对难实现的代码,只不过是将Swift代码和Objective-C代码桥接一下,功能同样实现而且省时省工,难道不好吗?

    参考链接

    相关文章

      网友评论

      • Go丶Pikachu:UIButton.harmlessFunction()为啥要这么写 不是所有类都会执行harmlessFunction()这个方法么
      • 退役程序猿:报错Cannot convert value of type 'AutoreleasingUnsafeMutablePointer<AnyClass?>' (aka 'AutoreleasingUnsafeMutablePointer<Optional<AnyObject.Type>>') to expected argument type 'AutoreleasingUnsafeMutablePointer<AnyClass>?' (aka 'Optional<AutoreleasingUnsafeMutablePointer<AnyObject.Type>>')
        Lin__Chuan:@明日香_4f9b 注意报错的说法, 只要你把<AnyClass?> 中的 ? 去掉就行了, 这里不加可选类型, 4.0以上的版本是这样用的
        明日香_4f9b:swift4会报这个错误,你知道怎么解决吗?

      本文标题:Swift3.x 继续 Method Swizzling

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