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