前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS runtime通过selector获取IMP地址

iOS runtime通过selector获取IMP地址

作者头像
用户6094182
发布2019-08-23 17:56:36
1.6K0
发布2019-08-23 17:56:36
举报
文章被收录于专栏:joealzhoujoealzhou

iOS runtime通过selector获取IMP地址

获取IMP地址有两种方法:

  • class_getMethodImplementation
  • (class_getInstanceMethod | class_getClassMethod) --> method_getImplementation

下面请看?(代码用swift在playground上完成)

代码语言:javascript
复制
//在swift中获取类名,需要类所在文件名.类名这样拼接。playground中bundleVersion就当做文件名
class Playground : NSObject {
    static var bundleVersion: String {
        let s = self.description().replacingOccurrences(of: ".Playground", with: "")
        return s
    }
}

class Person: NSObject {
    override init() {
        super.init()
        debugPrint("==============class_getMethodImplementation====================")
        getIMPFrom(sel: #selector(instanceFunc))
        getIMPFrom(sel: #selector(Person.classFunc))
        debugPrint("==============method_getImplementation====================")
        getIMPOfMethodFrom(sel: #selector(instanceFunc))
        getIMPOfMethodFrom(sel: #selector(Person.classFunc))
        debugPrint("==============================================================")
        getInstanceIMPFrom(sel: #selector(instanceFunc))
        getClassIMPFrom(sel: #selector(Person.classFunc))
    }
    
    @objc func instanceFunc() {
        debugPrint("instance func")
    }
    
    @objc class func classFunc() {
        debugPrint("class func")
    }
}
//在playground中创建一个Person对象
let p = Person()

一、使用class_getMethodImplementation获取IMP

代码语言:javascript
复制
/// 第一种方式获取IMP: class_getMethodImplementation
    func getIMPFrom(sel: Selector) {
        let clsName = "\(Playground.bundleVersion).Person"
        let instanceCls = objc_getClass(clsName)
        let instanceImp = class_getMethodImplementation(instanceCls as? AnyClass, sel)
        
        let classCls = objc_getMetaClass(clsName)
        let classImp = class_getMethodImplementation(classCls as? AnyClass, sel)
        
        debugPrint(instanceImp!, classImp!)
    }
"==============class_getMethodImplementation===================="
0x000000011defad20 0x0000000105f4da00
0x0000000105f4da00 0x000000011defaeb0

使用class_getMethodImplementation分别获取实例方法、类方法的IMP。打印出来有两个相同的地址0x0000000105f4da00,这是在调用class_getMethodImplementation时无法找到对应的实现方法。(你可以执行多次都会发现这两个地址虽然会变但都会相同)

二、(class_getInstanceMethod | class_getClassMethod) --> method_getImplementation

使用这种方式获取IMP,先通过class_getInstanceMethod获取实例方法method或者通过class_getClassMethod获取类方法method,再调用method_getImplementation方法获取IMP。通过打印分析:传入selector为实例方法时,会找不到对应的类方法实现。同理传入selector为类方法时,也会找不到对应的实例方法实现。

代码语言:javascript
复制
/// 第二种方式获取IMP:先获取method在获取IMP
    func getIMPOfMethodFrom(sel: Selector) {
        let clsName = "\(Playground.bundleVersion).Person"
        let cls = objc_getClass(clsName)
        if let instanceMethod = class_getInstanceMethod(cls as? AnyClass, sel) {
            let instanceImp = method_getImplementation(instanceMethod)
            debugPrint("instanceIMP: \(instanceImp)")
        } else {
            debugPrint("instanceIMP nil")
        }
        
        let mataCls = objc_getMetaClass(clsName)
        if let classMethod = class_getClassMethod(mataCls as? AnyClass, sel) {
            let classImp = method_getImplementation(classMethod)
            debugPrint("classIMP: \(classImp)")
        } else {
            debugPrint("classIMP nil")
        }
    }
"==============method_getImplementation===================="
"instanceIMP: 0x0000000125bc1d20"
"classIMP nil"
"instanceIMP nil"
"classIMP: 0x0000000125bc1eb0"

三、Tips

通过objc_getMetaClass获取的class是无法找到实例方法的实现的。然而使用objc_getClass获取的class能找到类方法的实现。

代码语言:javascript
复制
/// 使用getMetaClass获取实例方法IMP
    func getInstanceIMPFrom(sel: Selector) {
        let clsName = "\(Playground.bundleVersion).Person"
        let cls = objc_getMetaClass(clsName)
        if let method = class_getInstanceMethod(cls as? AnyClass, sel) {
            let instanceIMP = method_getImplementation(method)
            debugPrint("instanceIMP: \(instanceIMP)")
        } else {
            debugPrint("getMetaClass 无法获取实例方法")
        }
    }
    
    /// 使用getClass获取类方法
    func getClassIMPFrom(sel: Selector) {
        let clsName = "\(Playground.bundleVersion).Person"
        let cls = objc_getClass(clsName)
        if let method = class_getClassMethod(cls as? AnyClass, sel) {
            let classIMP = method_getImplementation(method)
            debugPrint("classIMP: \(classIMP)-------getClass 可以获取类方法")
        } else {
            debugPrint("getClass 无法获取类方法")
        }
    }
"=============================================================="
"getMetaClass 无法获取实例方法"
"classIMP: 0x0000000125bc1eb0-------getClass 可以获取类方法"
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.04.08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • iOS runtime通过selector获取IMP地址
    • 一、使用class_getMethodImplementation获取IMP
      • 二、(class_getInstanceMethod | class_getClassMethod) --> method_getImplementation
        • 三、Tips
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档