父子控制器和MJ框架底层RunTime思想(二)

一 父子控制器

控制器需要了解的知识:

1 谁modal,谁dismiss
—-> dismiss的原理:判断当前的通知其是否是modal出来的控制器,如果是那么就dismiss;判断父控制器是否是modal出来的控制器,如果是,那么就dismiss,如果不是,那么就逐级的往上找,一直判断,直到没有父控制器.
2 拿到导航控制器的条件
—–> // 只要是导航控制器的子控制器就能拿到导航控制器
—–> // 判断下当前控制器是否是导航控制器的子控制,判断下自己的父控制器是否是导航控制器的子控制器,继续寻找有没有父控制器
3 addSubView的原理:只要添加一个viewA,先判断viewA有没有父控件,如果有父控件,先将父控件移除,在重新添加到对应的view
4 一个通过运用父子控制器实现的案例
4.1 功能图:(类似于UITabBarController功能)

父子控制器和MJ框架底层RunTime思想(二)_第1张图片

—–> 原理:通过运用父子控制器的原理,我们始终只保证控制器的view只有一个.同时达到了控制器的切换,还有能监听选中后控制器的点击事件.
—–> 思路:
——-> 1上面部分的类似导航条的功能部分,采用一个view作为三个按钮的父控件.
——-> 2 创建三个控制器,我们都将控制器通过addChildViewController方法加入到父控制器中
——-> ​3 当点击不同的按钮的时候,我们不是将控制器加入 ,而是将控制器的view加入到父控件的view中
——-> ​4 如何保证程序运行中只有一个view呢?用一个普通的view来装容器,类似于UITabBarController一样装控件的view

代码块一:设置控制器

#pragma mark - 设置子控制器

- (void)setWithChildCode
{
    //创建控制器
    XFJHotViewController *hvc = [[XFJHotViewController alloc] init];

    //设置标题
    hvc.title = @"热点";

    //添加控制器到view中
    [self addChildViewController:hvc];

    //创建控制器
    XFJSocietyViewController *svc = [[XFJSocietyViewController alloc] init];
    svc.title = @"社会";

    //添加
    [self addChildViewController:svc];

    //创建控制器
    XFJTopLineViewController *lvc = [[XFJTopLineViewController alloc] init];
    lvc.title = @"头条";

    //添加
    [self addChildViewController:lvc];

}

代码块二:设置按钮

#pragma mark - 设置按钮

- (void)setWithBtn
{
    //拿到标题view的所有的子控件数
    NSInteger count = self.titleView.subviews.count;

    //遍历控件
    for (int i = 0; i < count; i++) {
        //取到对应的按钮
        UIButton *btn = self.titleView.subviews[i];

        //获取对应的控制器
        UIViewController *vc = self.childViewControllers[i];

        //设置按钮对应的标题
        [btn setTitle:vc.title forState:UIControlStateNormal];
    }  
}

代码块三:处理点击按钮的业务逻辑(采用直接拖线的方法)

#pragma mark - 按钮的业务逻辑
- (IBAction)titleBtnClick:(UIButton *)sender
{
    //遍历contentView中所有的子控制器(移除多余的控制器view,只保证只有一个view)
    for (UIView *view in self.contentView.subviews) {

        NSLog(@"%@",self.contentView.subviews);
        [view removeFromSuperview];
    }
    //根据tag.选择指定的控制器
    UIViewController *vc = self.childViewControllers[sender.tag];

    //设置控制器view的背景颜色
    vc.view.backgroundColor = sender.backgroundColor;

    //设置控制器view的尺寸
    vc.view.frame = self.contentView.bounds;

    //将控制器的view加入到contentView中
    [self.contentView addSubview:vc.view];
}

代码块四:设置一个view,用来装子控件的view(占位思想精华部分)

/** * 用来接收控制器的view */
@property (weak, nonatomic) IBOutlet UIView *contentView;
5 其实上面的思想是用到了占位的思想,就是先用一个view将父控件的view占住一个位置,然后通过占据的位置来处理业务,通常是在开发中常用的一种思想.

二 MJ框架底层RunTime思想(二级模型转换)

条件:当模型中嵌套了一个模型的时候,也就是说字典中又含有字典的时候,需要我们做二级转换.

步骤:

—-> 1 遍历模型中的属性
—-> 2 判断属性的类型是否是字典的类型,满足条件才可以二级转换
—-> 3 如果是,字典的类型,那么就调用自己实现一级模型转换
—-> 4 根据key和value给模型属性赋值

底层的代码部分:

+ (instancetype)modelWithDict:(NSDictionary *)dict
{
    //遍历模型中的属性,用字典中的属性给模型属性赋值
    //先创建一个模型
    id obj = [[self alloc] init];

    //初始化成员变量总数
    NSInteger count = 0;

    //取出成员属性列表(是一个数组)
    Ivar *ivarList = class_copyIvarList(self, &count);

    //遍历
    for (int i = 0; i < count; i++) {

        //获取成员变量
        Ivar ivar = ivarList[i];

        //获取成员变量的名称
        NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];

        //获取成员变量的类型
        NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];

        //替换(由于获取的成员变量的类型格式是@"\User\"这种类型的,需要我们将@"和\"替换掉)

        type = [type stringByReplacingOccurrencesOfString:@"@\"" withString:@""];
        type = [type stringByReplacingOccurrencesOfString:@"\"" withString:@""];

        //将成员变量的下划线截去掉
        NSString *key = [ivarName substringFromIndex:1];

        //从字典中取出对应的value(根据key)
        id value = dict[key];

        //判断只有是字典并且是自定义的才需要二级转换
        if ([value isKindOfClass:[NSDictionary class]] && ![type containsString:@"NS"]) {

            //获取类型
            Class className = NSClassFromString(type);

            //字典转模型
            value = [className modelWithDict:dict];
        }
        if (value) {
            //用key和value给模型中的属性赋值
            [obj setValue:value forKey:key];
        }
    }
    return obj;
}

三 总结

1 知道了MJ框架的底层实现,那么我们可以更加巧妙的利用MJ框架进行一些复杂的模型转换,同时我们甚至可以自己写框架,前提是有足够繁多的知识积累.

2 在开发中需要知道,当我们需要另外一种格式的控制器时,又想要和UITabBarController一样的功能的时候,我们完全可以自定义一个,同样而已达到功能的实现.

3 在开发中还有很多的不懂的地方,希望大家多多指教,谢谢!!!!

你可能感兴趣的:(框架,导航)