imp_implementationWithBlock()的實現機制
本文為大地瓜原創,歡迎知識共享,轉載請註明出處。
雖然你不註明出處我也沒什麼精力和你計較。
作者微訊號:christgreenlaw
本文的原文。本文只對其進行翻譯。
iOS 4.3中,有三個非常底層的runtime函式提供了一種新的OC和Blocks之間的橋樑,其目的是加強方法實現的動態生成(facilitating the dynamic generation of method implementations)。
具體一點來說:
IMP imp_implementationWithBlock(void *block);
void *imp_getBlock(IMP anImp);
BOOL imp_removeBlock(IMP anImp);
需要特別指明的是,imp_implementationWithBlock():
接收一個block引數,將其拷貝到堆中,返回一個trampoline(直譯為“蹦床”,大家意會吧),可以讓block當做OC任何一個類的方法的實現(implementation)--IMP--來使用(一個大前提是block的引數和方法的引數時匹配的)。
int j = 12;
IMP skewIMP = imp_implementationWithBlock(^(id _s, int k) { return k * j; });
這裡skewIMP
會包含一個函式指標,可以作為下面這樣宣告的方法的IMP:
- (int)skew: (int) k;
需要注意的是:imp_implementationWithBlock()
並不返回一個可以像function一樣呼叫的block的函式指標。其中的關鍵是:IMP總是最少有兩個引數:(id self, SEL _cmd)
。
要宣告一個block,你要丟棄掉SEL _cmd
,保留其它引數。
就像這樣:
-(void)doSomething:
void(*doSomethingIMP)(id s, SEL _c);
void(^doSomethingBLOCK)(id s);
-(void)doSomethingWith:(int)x;
void(*doSomethingWithIMP)(id s, SEL _c, int x);
void(^doSomethingWithBLOCK)(id s, int x);
-(int)doToThis:(NSString*)n withThat:(double)d;
int(*doToThis_withThatIMP)(id s, SEL _c, NSString *n, double d);
int(^doToThis_withThatBLOCK)(id s, NSString *n, double d);
這種模式的做法和OC以及Blocks的ABI(Application Binary Interface,應用程式二進位制介面)是有關係的。method其實就是開頭帶有兩個引數的C function:收到訊息的object以及正在執行的方法的selector。與之相似的是,呼叫Block就像開頭帶有一個引數的C function:一個block的引用(as described in the Block ABI on the llvm.org site)。
在我之前寫的 intimate tour of objc_msgSend()中我說過, 想讓objc_msgSend執行的更快,有以下幾個要求或者優化方式:
- 除非必要,不要碰registers
- 優化tail call
- 不要碰引數列表
imp_implementationWithBlock()
也是一樣的,返回的函式指標儘可能少地修改引數列表,然後呼叫block的實現。因此,它速度快,廣泛適用於方法實現。
關鍵就是,方法實現總是在引數列表起始處有兩個指標引數:self & _cmd
。trampoline用第一個引數(self
)重寫第二個引數(_cmd
)。將block 的引用放入第一個引數,最後呼叫block 的實現。
更重要的是,imp_implementationWithBlock()
所返回的函式指標--IMP--和別的IMP沒有區別。它可以被傳遞給任何接受IMP引數的API,傳遞給class_getMethod()
的 type string 和一個常規的 “編譯期IMP”沒有什麼區別。
沒了嗎?
block在觸發時,自身作為第一個引數,其他的引數,不管有多少,在這個過程中都留著不動。
另外兩個函式——imp_getBlock()
和imp_removeBlock()
——是為了完整性而提供的。很顯然,移除或銷燬一個方法的當前的IMP是應用中快速結束的好方式。
總結一下
Using Xcode 4.0 and iOS 4.3, create a new iOS View Based Application.
Replace the code in the provided main.m with the following:
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
@interface Answerer:NSObject
@end
@interface Answerer(DynamicallyProvidedMethod)
- (int)answerForThis:(int)a andThat:(int)b;
- (void)boogityBoo:(float)c;
@end
@implementation Answerer
@end
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int (^impyBlock)(id, int, int) = ^(id _self, int a, int b)
{
return a+b;
};
// grab an instance of the class we'll modify next
Answerer *a = [Answerer new];
// create an IMP from the block
int (*impyFunct)(id, SEL, int, int) = (void*) imp_implementationWithBlock(impyBlock);
// call the block, call the imp. Note the argumentation differences
NSLog(@"impyBlock: %d + %d = %d", 20, 22, impyBlock(nil, 20, 22));
NSLog(@"impyFunct: %d + %d = %d", 20, 22, impyFunct(nil, NULL, 20, 22));
// dynamically add the method to the class, then invoke it on the previously
// created instance (or we could create the instance after adding, doesn't matter)
class_addMethod([Answerer class], @selector(answerForThis:andThat:), (IMP)impyFunct, "i@:ii");
NSLog(@"Method: %d + %d = %d", 20, 22, [a answerForThis:20 andThat:22]);
// It is just a block; grab some state (the selector & a variable)
SEL _sel = @selector(boogityBoo:);
float k = 5.0;
IMP boo = imp_implementationWithBlock(^(id _self, float c) {
NSLog(@"Executing [%@ -%@%f] %f",
[_self class], NSStringFromSelector(_sel), c,
c * k);
class_addMethod([Answerer class], _sel, boo, "v@:f");
// call the method
[a boogityBoo:3.1415];
// clean up
[a release];
[pool release];
return 0;
}
And the output:
ImpityImp[2298:207] impyBlock: 20 + 22 = 42
ImpityImp[2298:207] impyFunct: 20 + 22 = 42
ImpityImp[2298:207] Method: 20 + 22 = 42
ImpityImp[2298:207] Executing [Answerer -boogityBoo:3.141500] 15.707500
相關文章
- Js非同步機制的實現JS非同步
- docker 實現 Redis 的哨兵機制DockerRedis
- Spring AOP 的實現機制Spring
- HashMap的內部實現機制HashMap
- spring aop的實現機制Spring
- MySQL中的MVCC實現機制MySqlMVC
- 併發機制的底層實現
- Nginx accept鎖的機制和實現Nginx
- Django許可權機制的實現Django
- NX實現機制淺析
- 事務機制如何實現
- FreeTextBox實現機制
- Redis的記憶體和實現機制Redis記憶體
- Kafka核心中的分散式機制實現Kafka分散式
- 深入理解事件機制的實現事件
- 詳解Apache Dubbo的SPI實現機制Apache
- [轉載]Spring AOP的實現機制Spring
- Binder機制分析(3)—— 實現自己的Service
- Android 的 Handler 機制實現原理分析Android
- Java 日誌快取機制的實現Java快取
- Python 中 import 的機制與實現PythonImport
- Spring IOC容器實現機制Spring
- Objective-C block 實現機制ObjectBloC
- NodeJS實現websocket代理機制NodeJSWeb
- Java反射機制實現與原理Java反射
- Oracle Mutex實現機制(轉帖)OracleMutex
- Java實現配置載入機制Java
- 深入探究immutable.js的實現機制(二)JS
- 利用反射機制實現依賴注入的原理反射依賴注入
- 深入探究Immutable.js的實現機制(一)JS
- Nestjs模組機制的概念和實現原理JS
- Redis Sentinel實現的機制與原理詳解Redis
- C++ 異常處理機制的實現C++
- Java中常用快取Cache機制的實現Java快取
- Redisson的看門狗機制底層實現Redis
- JAVA的反射機制==>用反射分析類的實現Java反射
- Istio流量管理實現機制深度解析
- Android RollBack機制實現原理剖析Android