美文网首页CoderHG.iOS程序员iOS Developer
iOS开发中、如何选择重写初始化方法?

iOS开发中、如何选择重写初始化方法?

作者: CoderHG | 来源:发表于2017-04-29 14:17 被阅读537次
    天地之仁,故万物皆屌丝

    说在前面的话

    很多时候,我们总是需要重写父类的方法达到我们开发需求。那么在iOS开发过程中,会有哪些初始化方法呢?又应该注意些什么问题?比如在一个自定义的UIView子视图中, 如果重写了initWithFrame:方法, 为什么不应该再重写init方法。

    可以先下载项目HGInitManager

    强调

    • 1、只谈现象,不谈实质原理。
    • 2、重点在乎的是如何选择,而不是对与错。

    类方法

    + (instancetype)new;
    

    对于这个方法,具体的原理应该(不确定)如下所示:

    + (instancetype)new {
        return [[self alloc] init];;
    }
    

    这个类方法,实际上还是调用了 init 实例方法,在接下来会谈到 init 方法,所以这里不做过多的介绍。在我开发这么长的时间还真没有重写过 ** new 方法** ,感觉也没有必要。所以今天暂且不谈。

    实例方法

    在介绍实例的初始化方法的时候,我将采取 MVC 的设计模式向大家介绍。

    Model 层

    Model层一般都叫模型类:特指直接或间接继承NSObject的类。主要是把 UIView 与 UIViewController 区别开,当然UIView 与 UIViewController 也是集成于NSObject。

    init

    这个方法是所有OC对象类都有的方法,所以所有的对象类都可以重写。重写样例如下:

    - (instancetype)init {
        self = [super init];
        
        // TODO: 给当前self做默认设置
        
        return self;
    }
    
    

    回头看看本文的标题<iOS开发中、如何选择重写初始化方法?>。那么问题来了,这个方法对所有的对象类都通用,我们在什么时候重写才显得更高大上呢?我的建议是:仅仅在模型类(Model)中,才去重写。
    例子:

    - (instancetype)init {
        self = [super init];
        
        // 设置默认年龄是 18
        self.age = 18;
        
        return self;
    }
    

    对,你没有看错。仅仅在 Model 中对数据的默认设置的时候,才有必要重写这个方法。

    聪明的你会问,在 UIView 与 UIViewController 中就不可以重写这个方法么?请回到我强调的第二点(2、重点在乎的是如何选择,而不是对与错。)。

    在这里我想先说一下的是:在 UIView 与 UIViewController 中坚决不要重写 init 方法。在接下来会介绍在 UIView 与 UIViewController 中应该如何选择重写 初始化方法。

    View 层

    在这里要清楚的一点是,在 View 层有两种方式加载 View :纯代码与XIB(SB)。这里要区分来介绍,因为这两种方式的初始化方法是两套机制。

    纯代码

    大家应都知道,纯代码创建 View 有两个方法提供选择,分别是:

    - (instancetype)init
    {
        self = [super init];
        
        // TODO: 给当前视图做默认设置
        
        NSLog(@" init ");
        
        return self;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        
        // TODO: 给当前视图做默认设置
        
        NSLog(@" initWithFrame: ");
        
        return self;
    }
    
    

    那么问题又来了,这两个方法在 View 中,我们应该如何选择呢?两个都要重写,还是只要重写其中一个?带着这个问题,我们创建一个继承于 UIView 的HGInitView。并且将上面的代码copy到 .m 文件中。

    我们在其它地方用来年各种功能方式创建:
    方式1:

    HGInitView* hgView = [[HGInitView alloc] initWithFrame:CGRectZero];
    

    打印日志如下:

    initWithFrame:

    打印结果 证明: 仅仅触发了 initWithFrame: 方法。这结果其实没有什么可惊讶的,我们再来看看方式2。

    方式2:

    HGInitView* hgView = [[HGInitView alloc] init];
    

    打印日志如下:

    0.png

    打印结果 证明: 即触发了 initWithFrame: 方法 又触发了init 方法。问题来了,如果我用方式2来创建视图的话,不久重复了么?

    最终结论:

    • 两种方式都能正确的创建试图。
    • 两种方式都会触发initWithFrame: 方法。

    所以在这里的建议是:在 UIView 的子类中不要重写 init 方法,重写 initWithFrame: 方法就足够了。

    XIB

    也有两种方式给当前的试图做初始化。分别是:

    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        
        // TODO: 给当前视图做默认设置
        self.hgLabel.textColor = [UIColor redColor];
        
        NSLog(@"initWithCoder:");
        
        return self;
    }
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        
        // TODO: 给当前视图做默认设置
        self.hgLabel.textColor = [UIColor redColor];
        
        NSLog(@"awakeFromNib");
        
    }
    
    

    在这里只有一种方式来加载视图,代码如下:

    NSArray* views =  [[NSBundle mainBundle] loadNibNamed:@"HGInitView" owner:nil options:nil];
        HGInitView* hgView = views.firstObject;
    

    打印日志如下:

    XIB 文件加载视图

    同样两个方法都调用了,并且一切都很正常。现在我有目的的将 awakeFromNib 方法注释,看看效果。很惊讶的发现‘self.hgLabel.textColor = [UIColor redColor];’这句代码没有效果,这是为什么呢?请看下图:

    解惑

    答案就在上图中,当执行 initWithCoder: 方法的时候,当前试图中的子试图还没有值。所以在个方法中给子试图设置默认效果是无效的。这里只能给其它的属性做默认设置。

    这里就不用看只打开 awakeFromNib方法的效果了。在这个方法中,什么都有,什么都可以设置了。

    这里也提醒大家:initWithCoder: 方法一般是用于资源文件加载用,一般用于 解档 时用到。一般情况要慎用。

    综上所属: 在XIB视图加载中,一般重写awakeFromNib方法就可以了。

    View 层总结:

    • 纯代码创建试图,重写 initWithFrame: 方法就足够。
    • XIB 加载视图,重写awakeFromNib方法就足够。

    如果当前视图可能用于纯代码,也可能用于XIB 加载,一般是在封装控件的时候比较多。那么按照下图中的写,就够了:

    View 层通用

    Controller 层

    同样 Controller 也有两种方式加载。与之相关的方法如下:

    
    - (instancetype)init {
        self = [super init];
        
        // TODO: 默认设置
        
        return self;
    }
    
    - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        
        // TODO: 默认设置
        self.hgLabel.textColor = [UIColor redColor];
        
        return self;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // TODO: 默认设置
        self.hgLabel.textColor = [UIColor redColor];
    }
    
    

    在这里,我就不带着大家一一分析了。直接把我的建议分享给大家,同时也是希望大家动手试试。在这里要强调一点的是 viewDidLoad 说成是初始化方法,真的也有点搞笑 。但是希望你先把我的建议看完,再好好的笑一笑。

    笑一笑

    我的建议是:

    • 1、直接在 viewDidLoad 方法中直接对所有的默认做设置。
    • 2、在initWithNibName: bundle:方法做非视图的默认设置,在viewDidLoad 方法中做与视图有关的默认设置。
    • 言之总而:在init开头的方法中,不要做与视图有关的设置。

    感谢看到这里的小伙伴!到这里,本文就算是结束了,有什么问题,欢迎大家讨教与骚扰。

    也可以下载项目HGInitManager

    相关文章

      网友评论

        本文标题:iOS开发中、如何选择重写初始化方法?

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