博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Swift3中的 Method Swizzling
阅读量:6799 次
发布时间:2019-06-26

本文共 2975 字,大约阅读时间需要 9 分钟。


先聊聊Method Swizzling

从 Objective-C 开始, runtime一直是解决坑爹需求和面试装逼的一大利器,然而聊起 runtime 很多人都第一个想到 Method Swizzling,.因为 Objective-C中调用方法都是动态实现的,当运行时的才确定到底执行哪个方法,而 Method Swizzling 就是利用这个特点来解决很多问题.

现在关于 Runtime 和 Method Swizzling 的文章太多了,我推荐一篇: 大神写的关于 runtime这几篇,看完基本对 runtime 就没什么问题了吧...

再看看 Swift3.0中的 Method Swizzling

先来看看 swizzling 在 Objective-C 中的注意点:(对比上文链接中)

1.Swizzling应该总在category的 +load中执行 ( Objective-C )

那在 Swift 中, extension 并不是运行时加载的, 因此也没有加载时候就会被调用的类似 +load 的方法. 事实上,Swift 实现的 load 并不是在 app 运行开始就被调用的。基于这些理由,我们使用另一个类初始化时会被调用的方法来进行交换:

open override static func initialize() {    // Method Swizzling}复制代码

这一条部分来自喵神 swiift tips 第二版, 喵神在第三版中删除了 swizzling 这个章节,理由是这部分更多是 Objective-C的内容. 我个人觉得如果在 Swift 中还需要用 Swizzling 这种技术来实现需求, 不如用更 Swifty的方式去解决问题, 函数式或者面向协议等等等?

2.Swizzling应该总是在dispatch_once中执行

那么,问题来了,在3.0版本 dispatch once 已经被废弃,这怎么办?

刚巧的是前几天群里的老司机 写了篇

通过给DispatchQueue实现一个扩展方法来实现 Dispatch once. 至于没什么要 dispatch_once呢? 因为 Swizzling会改变全局状态,所以用dispatch_once来确保无论多少线程都只会被执行一次.

3. Swift自定义类中使用 Method Swizzling

因为Method Swizzling的实现是基于 Objective-C 的动态派发机制,所以有两条限制 1.包含 swizzle 方法的类需要继承自 NSObject 2.如果要 Swizzle 的是 Swift 类型的方法的话,需要将原方法和替换方法都加上 dynamic 标记,以指明它们需要使用动态派发机制


上个 sample:

extension UIViewController {    open override static func initialize() {        struct Static {            static var token = NSUUID().uuidString        }        if self != UIViewController.self {            return        }        DispatchQueue.once(token: Static.token) {             let originalSelector = #selector(UIViewController.viewWillAppear(_:))            let swizzledSelector = #selector(UIViewController.xl_viewWillAppear(animated:))            let originalMethod = class_getInstanceMethod(self, originalSelector)            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)                        //在进行 Swizzling 的时候,需要用 class_addMethod 先进行判断一下原有类中是否有要替换方法的实现            let didAddMethod: Bool = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))            //如果 class_addMethod 返回 yes,说明当前类中没有要替换方法的实现,所以需要在父类中查找,这时候就用到 method_getImplemetation 去获取 class_getInstanceMethod 里面的方法实现,然后再进行 class_replaceMethod 来实现 Swizzing            if didAddMethod {                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))            } else {                method_exchangeImplementations(originalMethod, swizzledMethod)            }        }    }    func xl_viewWillAppear(animated: Bool) {        self.xl_viewWillAppear(animated: animated)        print("xl_viewWillAppear in swizzleMethod")    }}extension DispatchQueue {    private static var onceTracker = [String]()    open class func once(token: String, block:() -> Void) {        objc_sync_enter(self)        defer { objc_sync_exit(self) }        if onceTracker.contains(token) {            return        }                onceTracker.append(token)        block()    }}复制代码

转载地址:http://fcywl.baihongyu.com/

你可能感兴趣的文章
Array.from方法具体理解(3分钟)
查看>>
CS229课程01-机器学习的动机与应用
查看>>
iOS开发常用框架总览!
查看>>
Javascript实现冒泡排序与快速排序以及对快速排序的性能优化
查看>>
深入React v16新特性(一)
查看>>
笔记(2) 从webpack到vue-cli3.0
查看>>
记一次阿里巴巴一面的经历
查看>>
用前端 最舒服的躺姿 "搞定" Flutter (组件篇)
查看>>
Android开发无线调试工具adbwireless的使用简介(附AirADB)
查看>>
ContentProvider 详解
查看>>
简单优化容器服务
查看>>
TCP详解
查看>>
重学ES6 数组扩展(2)
查看>>
你会这道阿里多线程面试题吗?
查看>>
行云管家V4.9正式发布:监控全面提升,首页、主机详情大幅优化,新增大量实用功能.md...
查看>>
采用镜像部署LNMP 环境操作步骤
查看>>
不服?来跑个分!
查看>>
Python笔记 开发环境搭建
查看>>
ios logo 启动页大小
查看>>
(四)构建dubbo分布式平台-maven代码结构
查看>>