Runtime學習筆記,一個簡單的例子來演示下Runtime消息機制
- 創建一個控制檯應用,在main.m中
int main(int argc, const char * argv[]) {
@autoreleasepool {
id objc = [NSObject alloc];
objc = [objc init];
}
return 0;
}
打開控制檯,cd到main.m文件所在文件夾,輸入
clang -rewrite-objc main.m
,然後你發現在文件夾中會多出一個main.cpp的c++文件。打開main.cpp文件,wtf?!上十萬行代碼……
cmd+F
搜索@autoreleasepool
,你會找到最開始寫的那段代碼的底層實現代碼
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
id objc = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc"));
objc = ((id (*)(id, SEL))(void *)objc_msgSend)((id)objc, sel_registerName("init"));
}
return 0;
}
- 去掉所有強制轉換,下面的代碼是不是看起來就很熟悉了呢?
id objc = objc_msgSend(objc_getClass("NSObject"),sel_registerName("alloc"));
objc = objc_msgSend(objc,sel_registerName("init"));
利用Runtime消息機制,我們可以訪問別人寫的一些私有方法,而不去改變別人的代碼(私自改變別人的代碼是要喫砍刀的,切記,切記)
- 創建一個Person對象,開放一個方法- eat,創建一個私有方法- count:
//Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
-(void)eat;
@end
//Person.m
#import "Person.h"
@implementation Person
-(void)eat{
NSLog(@"喫東西");
}
-(void)count:(int)num{
NSLog(@"count:%d",num);
}
@end
//ViewController.m
#import "ViewController.h"
#import "Person.h"
#import <objc/message.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = objc_msgSend(objc_getClass("Person"), sel_registerName("alloc"));
p = objc_msgSend(p, sel_registerName("init"));
objc_msgSend(p, sel_registerName("eat"));
//在這裏,count:方法是私有的。對於有參的方法,在後面按照順序逗號隔開寫參數就好。
objc_msgSend(p, sel_registerName("count:"),3);
}
-(void)test{
//1.導入<objc/message.h>
//2.在Build Settings 中搜索msg,設置爲NO
//3.使用runtime
id objc = objc_msgSend([NSObject class], @selector(alloc));
objc = objc_msgSend(objc, @selector(init));
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end