iOS开发之Xib继承问题

作者: CoderFM | 来源:发表于2017-07-23 21:41 被阅读320次

    概述

    为了快速开发, 项目多出用到xib, xib的复用问题就一直存在, 最近不是很忙, 在想这个问题, 本来的加载xib的方法就是写在分类里的, 所以都是调用一个方法, 若想实现统一方法调用, 或许可以实现重写分类的方法, 但是每一个子类都要重写才能正确, 很麻烦, 就没有去实现了, 反正总体的思路就是先从自己的加载, 没有就加载父类的, 一层层往上找, 所以就有了我这篇文章
    按照惯例要上demo

    要解决两个问题:

    1. 子类没有xib 然后从父类 一直往上找
    2. 实例化出来的对象的实际类型并不是当前子类 改变为当前的子类

    首先解决第一个问题
    我是基于分类写的:

    + (instancetype)fm_viewFromXib{
        UIView *view = nil;
        NSArray *views = nil;
        views = [self fm_loadFromNib];
        if (views == nil) {
            return [[self alloc] init];
        }
        view = views.lastObject;
        if (view == nil) {
            return [[self alloc] init];
        }
        object_setClass(view, self);
        return view;
    }
    

    优先从xib加载, 没有的从代码实例化一个返回出去
    具体来再看看fm_loadFromNib这个方法

    + (NSArray *)fm_loadFromNib{
        if ([self fm_loadNibFromName:NSStringFromClass(self)]) {
            return [self fm_loadNibFromName:NSStringFromClass(self)];
        } else {
            NSArray *arrM = nil;
            NSString *name = NSStringFromClass([super class]);
            while (![name isEqualToString:NSStringFromClass([UIResponder class])]) {
                name = [self fm_xibFileName];
                if ([self fm_loadNibFromName:name]) {
                    arrM = [self fm_loadNibFromName:name];
                    break;
                } else {
                    Class superClass = NSClassFromString(name);
                    superClass = class_getSuperclass(superClass);
                    name = NSStringFromClass(superClass);
                }
            }
            return arrM;
        }
    }
    

    if判断如果当前的类名的xib是可以加载出来的, 就直接返回房钱自己加载的 如果没有就从父类, 父类不知道有多少级, 所以就有一个while循环, 只要类不是UIResponder类 UIView的父类是UIResponder, 所以循环到UIResponder就停止
    下面用了一点runtime的Api取父类, 我这里先去名字, 再从名字中获取Class, 一开始我是想用super的, 发现根本不行, 因为你调用的是父类的发放, 但是类型还是自己, 所以就我暂且想到这个方法

    + (NSArray *)fm_loadNibFromName:(NSString *)name{
        if ([self fm_isExsitNibWithName:name]) {
            return [[NSBundle mainBundle] loadNibNamed:name owner:nil options:nil];
        }
        return nil;
    }
    
    + (BOOL)fm_isExsitNibWithName:(NSString *)name{
        return [[NSBundle mainBundle] pathForResource:name ofType:@"nib"] != nil;
    }
    

    以上两个方法, 判断Bundle有没有nib这个文件, 这里也踩过一个坑, 想到用UINib去实例化看看有没有, 然后发现当没有这个对应的nib文件去创建对象的时候就挂了, 总的来说这个问题解决了, 可能并不是那么的优雅

    第二个问题代码中已经贴了

    object_setClass(view, self);
    

    将当前实例化出来的对象的isa指向当前类, 调用子类的自己的方法就不会奔溃了

    暂时xib默认的名字类名, 为了防止有不一样的, 可以自定义, 继承之后, 重写fm_xibFileName方法即可

    总结

    有一点待优化的就是 不同Bundle下的文件的继承就出问题了 这里加载xib的时候 可以给个Bundle的参数 可以解决这个问题

    对于xib重度使用的人而言应该有点帮助吧

    如果觉得对你有一点帮助, 那就动动手指点个赞吧

    我的github
    不是很擅长言辞, 但是比较喜欢研究一些问题, 如果你有问题, 或者我们可以交流交流, 不能保证给你解决, 或许能提供另一种思路

    相关文章

      网友评论

        本文标题:iOS开发之Xib继承问题

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