Delegate的IMP缓存
来源:互联网 发布:搞笑的网络短剧 编辑:程序博客网 时间:2024/06/05 16:23
在objective-c中,所有的[receiver message:...]方法调用最终都会以obj_msgSend(recevier, @selector(message), …)的形式执行,这相比于c/c++的直接调用多少会有点影响,《深入分析 objc_msgSend》这篇文章主要分析了objc_msgSend具体需要执行的操作和可能的实现源码。
在WebKit的源码中就使用了将delegate中selector的IMP全部缓存起来的方式,然后在调用的时候直接调用而非通过obj_msgSend的形式来执行,下面根据WebKit的源码简单写了一下delegate缓存的实现。
缓存数据结构:
首先我们需要一个数据结构来缓存所有相关的delegate方法。
typedef struct _MyDelegateImplementationCache { IMP logMessage; IMP shouldDisMiss;} MyDelegateImplementationCache;
然后在delegate的setter函数中除了设置delegate变量,还需要做的一件事就是初始化delegate相关的方法缓存;
delegate的setting方法;
- (void)setMydelegate:(id<MyDelegate>)mydelegate{ _mydelegate = mydelegate; // Initialize the Delegate Implementation Cache. [self_cacheMyDelegateImplementations];}- (id<MyDelegate>)mydelegate{ return_mydelegate;}
初始化缓存:
static inline IMP getMethod(id o, SEL s){ return [o respondsToSelector:s] ? [o methodForSelector:s] : 0;}- (void)_cacheMyDelegateImplementations{ MyDelegateImplementationCache *cache = &(_delegateCache); id delegate = self.mydelegate; if (!delegate) { bzero(cache, sizeof(MyDelegateImplementationCache)); return; } // Get all the method's implecation and cache it in a struct. cache->logMessage = getMethod(delegate, @selector(logMessage:)); cache->shouldDisMiss = getMethod(delegate, @selector(shouldDisMiss));}
然后写几个对应的直接调用缓存中IMP的wrapper:
id CallDelegateString(IMP impletation, id delegate, SEL selector, NSString* arg1){ if (!delegate || ![delegate respondsToSelector:selector]) return nil; @try { id result =(id)((id (*)(id, SEL, NSString*))(impletation)(delegate, @selector(selector), arg1)); return result; } @catch(id exception) { ReportDiscardedDelegateException(selector, exception); } returnnil;}BOOL CallDelegateReturnBOOL(IMP impletation, id delegate, SEL selector){ if (!delegate || ![delegate respondsToSelector:selector]) return NO; @try { BOOL result =(BOOL)((BOOL (*)(id, SEL))(impletation)(delegate, @selector(selector))); return result; } @catch(id exception) { ReportDiscardedDelegateException(selector, exception); } return NO;}
最后在需要调用delegate方法的时候通过调用wrapper来替代用[delegate message:…]的方式来调用。
// Call the method from the delegate cache.CallDelegateString(_delegateCache.logMessage, self.delegate, @selector(logMessage:), @"the delegate method's impletation has been cached!\n");BOOL ret = CallDelegateReturnBOOL(_delegateCache.shouldDisMiss, self.delegate, @selector(shouldDisMiss));
那么,为什么WebKit仅针对delegate的这种方式来现实[delegate message:…]的IMP缓存,这是因为delegate都被声明为id类型,而objective-c的runtime机制向id类型的对象发送消息又比向确定类型的对象发送消息要满一点,仿照《深入分析 objc_msgSend》中的方法对这两种情况做了一个简单的测试:
START for (NSUInteger i = 0; i < LOOP; ++i) { [self.viewController logMessage:nil]; } END START for (NSUInteger i = 0; i < LOOP; ++i) { [self.mydelegate logMessage:nil]; } END
测试结果为:[self.viewController logMessage:nil] Cost:898.973000; [self.mydelegate logMessage:nil] Cost:1420.758000。
另外,WebKit的wrapper是用c++来实现的,其中用到了模版类,具体的实现如下,这里的实现是c实现,如果需要扩展其他的参数形式可能要麻烦一些,是不是有点java中jni的感觉。
static inline id CallDelegate(WebView *self, id delegate, SEL selector, NSRect rect){ if (!delegate || ![delegate respondsToSelector:selector]) return nil; @try { return wtfObjcMsgSend<id>(delegate, selector, self, rect); } @catch(id exception) { ReportDiscardedDelegateException(selector, exception); } returnnil;}template<typename RetType>RetType wtfObjcMsgSend(id target, SEL selector){ return reinterpret_cast<RetType (*)(id, SEL)>(objc_msgSend)(target, selector);}
- Delegate的IMP缓存
- Oracle IMP-00010、IMP-00031的解决
- Oracle IMP-00010、IMP-00031的解决
- exp/imp的Bug??
- imp/exp的使用方法
- imp exp的使用
- 查找 IMP 的过程
- EXP IMP的使用
- oracle的imp导入
- IMP指针的作用
- oracle 的exp imp
- exp、imp的特点
- imp.load_source的用法
- [C#-2] delegate和Delegate的区别
- imp
- imp
- imp
- IMP
- Discuz!X2.5论坛在IIS和Apache环境配置实现伪静态
- 用 new 还是用 alloc/init
- 关于python——面向对象开发
- 鲶鱼和害群之马
- android布局(2)表格布局
- Delegate的IMP缓存
- Makefile中VPATH的使用
- IT从业人员需要知道的安全知识
- 缓存cache使用示例
- platform设备驱动全透析
- android布局(3)相对布局
- Z-STACK之cc2530 flash驱动详解上
- 使用 Eclipse 和 Java SE 6 创建独立 Web Services 应用程序,第 2 部分: Web 服务客户端应用程序
- MFC 小知识总结四