美文网首页
iOS runtime 之跳转页面以及动态添加属性

iOS runtime 之跳转页面以及动态添加属性

作者: 丨Majestic灬磊 | 来源:发表于2019-05-20 15:25 被阅读0次

    序言

    runtime 的主要用处有以下几点:

    • 给分类添加属性
    • 消息转发机制
    • 动态交换方法的实现
    • 手动实现多继承(oc本身是不支持多继承的)

    今天主要是用runtime实现页面跳转以及动态添加属性,主要应用于手机App通过推送过来的数据内容来跳转不同的界面,并把界面数据展示出来或者是手机内部根据不同的cell的点击事件,不同的数据跳转不同的界面

    原理

    通过数据中带的Class类名来判断是否存在这个类
    存在:直接通过Class实例化,KVC绑定一下数据源,PushController里面
    不存在:动态创建Class类以及变量,实例化后通过KVC绑定一下数据源,PushController里面

    主要方法

    //创建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

    相关文章

      网友评论

          本文标题:iOS runtime 之跳转页面以及动态添加属性

          本文链接:https://www.haomeiwen.com/subject/ktmkzqtx.html