序言
runtime 的主要用处有以下几点:
- 给分类添加属性
- 消息转发机制
- 动态交换方法的实现
- 手动实现多继承(oc本身是不支持多继承的)
今天主要是用runtime实现页面跳转以及动态添加属性,主要应用于手机App通过推送过来的数据内容来跳转不同的界面,并把界面数据展示出来或者是手机内部根据不同的cell的点击事件,不同的数据跳转不同的界面
原理
通过数据中带的Class类名来判断是否存在这个类
存在:直接通过Class实例化,KVC绑定一下数据源,Push到Controller里面
不存在:动态创建Class类以及变量,实例化后通过KVC绑定一下数据源,Push到Controller里面
主要方法
//创建Class
objc_allocateClassPair(Class superclass, const char * name, size_t extraBytes)
//注册Class
void objc_registerClassPair(Class cls)
//添加变量
class_addIvar(Class cls, const char * name,size_t size, uint8_t alignment , const char * types)
//添加方法
class_addMethod(Class cls, SEL name, IMP imp, const char * types)
//获取属性
class_getProperty(Class cls, const char * name)
//获取实例变量
class_getInstanceVariable(Class cls, const char * name)
代码实现
1、工程中新建三个控制器,命名为
RLGongZhongHaoViewController
RLWechatViewController
RLQQQunViewController
RLJianShuViewController
然后在ViewController模拟根据不同数据跳转不同界面,代码如下
#import "ViewController.h"
#import <objc/message.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UISegmentedControl *segment;
@property (nonatomic, copy) NSString *classStr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.segment.selectedSegmentIndex = 0;
}
- (IBAction)selectAnyOne:(id)sender {
// switch (self.segment.selectedSegmentIndex) {
// case 0:
// _classStr = @"RLWechatViewController";
// break;
// case 1:
// _classStr = @"RLQQQunViewController" ;
//
// break;
// case 2:
// _classStr = @"RLGongZhongHaoViewController" ;
//
// break;
// case 3:
// _classStr = @"RLJianShuViewController" ;
//
// break;
//
// default:
// break;
// }
//
}
- (IBAction)pushGo:(id)sender {
[self pushToAnyWhere:_classStr];
}
- (void)pushToAnyWhere:(NSString *)class{
//将String转化成class类型
const char * className = [class UTF8String];
Class cls = objc_getClass(className);
//2.创建实例对象,给属性赋值
id instance = [[cls alloc]init];
//2.跳转到对应的界面
[self.navigationController pushViewController:instance animated:YES];
}
- (IBAction)pushGoWithData:(id)sender {
NSDictionary * infoDic = nil;
switch (self.segment.selectedSegmentIndex) {
case 0:
infoDic = @{@"class":@"RLWechatViewController",
@"property":@{
@"wechat":@"lei290138645"
}
};
break;
case 1:
infoDic = @{@"class":@"RLQQQunViewController",
@"property":@{
@"qq":@"290138645"
}
};
break;
case 2:
infoDic = @{@"class":@"RLGongZhongHaoViewController",
@"property":@{
@"gongzhonghao":@"iOS每日推"
}
};
break;
case 3:
//NewViewController
infoDic = @{@"class":@"RLJianShuViewController",
@"property":@{
@"jianshu":@"丨Majestic灬磊"
}
};
break;
case 4:
//NewViewController
infoDic = @{@"class":@"newViewController",
@"property":@{
@"new":@"公众号名称:iOS每日推",
@"des":@"本页面运行时创建"
}
};
break;
default:
break;
}
[self pushToControllerWithData:infoDic];
}
-(void)pushToControllerWithData:(NSDictionary * )vcData{
//1.获取class
const char * className = [vcData[@"class"] UTF8String];
Class cls = objc_getClass(className);
if(!cls){
//创建新的类,并添加变量和方法
Class superClass = [UIViewController class];
cls = objc_allocateClassPair(superClass, className, 0);
//添加phoneNumber变量
class_addIvar(cls, "new", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
class_addIvar(cls, "des", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
//添加titleLab控件
class_addIvar(cls, "titleLab", sizeof(UILabel *), log2(sizeof(UILabel *)), @encode(UILabel *));
//添加方法,方法交换,执行viewDidLoad加载
Method method = class_getInstanceMethod([self class], @selector(newLoad));
IMP methodIMP = method_getImplementation(method);
const char * types = method_getTypeEncoding(method);
class_addMethod(cls, @selector(viewDidLoad), methodIMP, types);
}
//2.创建实例对象,给属性赋值
id instance = [[cls alloc]init];
NSDictionary * values = vcData[@"property"];
[values enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
//检测是否存在为key的属性
if(class_getProperty(cls, [key UTF8String])){
[instance setValue:obj forKey:key];
}
//检测是否存在为key的变量
else if (class_getInstanceVariable(cls, [key UTF8String])){
[instance setValue:obj forKey:key];
}
}];
//2.跳转到对应的界面
[self.navigationController pushViewController:instance animated:YES];
}
-(void)newLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
//初始化titleLab
[self setValue:[[UILabel alloc]initWithFrame:CGRectMake(0, 100, [[UIScreen mainScreen] bounds].size.width, 50)] forKey:@"titleLab"];
UILabel * titleLab = [self valueForKey:@"titleLab"];
titleLab.numberOfLines = 0;
titleLab.textAlignment = NSTextAlignmentCenter;
//添加到视图上
[[self valueForKey:@"view"] performSelector:@selector(addSubview:) withObject:titleLab];
titleLab.text = [NSString stringWithFormat:@"%@\n%@", [self valueForKey:@"new"],[self valueForKey:@"des"]];
titleLab.textColor = [UIColor whiteColor];
}
@end
扫描下方公众号👇回复【runtime】获取源码
公众号扫描二维码.png
网友评论