关于从xib加载视图

来源:互联网 发布:淘宝网怎么找店主 编辑:程序博客网 时间:2024/06/05 09:50

作者:Love@YR
链接:http://blog.csdn.net/jingqiu880905/article/details/51745617
请尊重原创,谢谢

经常会看到initWithNibName,initWithCoder,awakeFromNib,loadNibNamed 这些方法,各种头大,网上资料不少,能说清楚的不多,于是今天写了个demo来测试下这些方法何时调用。

首先,我们从视觉上区分一下loadNibName和initWithNibName。
initWithNibName 是由UIViewController及其子类调用
如:

     AViewController *avc = [[AViewController alloc]initWithNibName:@"AViewController" bundle:nil];

而loadNibName则是这样:

 NSArray *objectsInNib = [[NSBundle mainBundle] loadNibNamed:@"BView" owner:nil options:nil]; for(id item in objectsInNib){if([item isKindOfClass:[yourview class]]){//找到了你需要的对象,do what you want}

在这个时候生成后会让引用计数器变为1,但是需要注意得owner:self ,在owner自己dealloc得时候,系统会自动帮你将你得youview得引用计数器-1。

在xib里,第一种(一般我们创建 viewcontroller时勾选了nib生成的)
通常是这样的:
这里写图片描述

注意这里的file’s owner是你的view controller类

这里写图片描述

底下这个view就是这个view controller的根view

第二种通常是这样的:

这里写图片描述

注意看,这里的file’s owner是NSObject

这里写图片描述

这里我拖了3个控件,其中view这个所属的类名为BView,同样其它控件我也需要给它创建类并连接。

这里写图片描述

默认uiview占满屏,改下其size为freeform即可改变其大小。

一般来说我们调用loadNibNamed的到的数组即这个xib上的所有控件,我们是想要拿一些控件如view,cell等而不是viewcontroller。(这也是最常用的用途)
但是,这里我们同样可以拖入viewcontroller, navigationcontroller等任意对象。
如图:

这里写图片描述

那么这里我们得到的数组里就能有viewcontroller这个对象了。
那么同样两种创建viewcontroller的方法,分别调用了什么呢?
测试结果显示用initWithNibName方法,会调用此CustomViewController的initWithNibName,viewDidLoad

而用loadNibNamed时,执行到此句时,就会调用此数组里所有对象的initWithCoder,awakeFromNib方法。
比如我在一个xib里加入了一个view,两个view controller。执行的log显示当调用loadNibNamed时打印了:
BView——-initWithCoder———-called
AVC——-initWithCoder———-called
bVC——-initWithCoder———-called
BView——-awakeFromNib———-called
AVC——-awakeFromNib———-called
bVC——-awakeFromNib———-called
然后我拿出aVC对象,present,并没有执行AVC的viewDidLoad。
这个问题 http://www.cnblogs.com/iOS-mt/p/4362335.html 这篇文章也说了,后续再研究。
这下清晰多了。
然后 http://blog.csdn.net/richard_rufeng/article/details/26508977 这篇文章说initWithNibName方法是延迟加载 loadNibNamed方法是即时加载,具体原理先不管了。就这样。

——————————我是分割线———————————————-

上面说了loadNibNamed方法一般用来加载控件对象的。下面我们来看用此方法生成一个CustomView对象和直接alloc一个此对象调用的方法有何区别:

在某个controller里我创建了avc并present

AViewController *avc = [[AViewController alloc] init];  [self presentViewController:avc animated:YES completion:nil];

在AViewController的viewDidLoad里:

    NSArray *bvarr = [[NSBundle mainBundle] loadNibNamed:@"BView"  owner:nil options:nil];    BView *bv = [bvarr objectAtIndex:0];//    [bv setFrame: CGRectMake(10, 10, 100, 100)];//此句话无效    [self.view addSubview:bv];

这里BView.xib里只有一个UIView的子类BView。和上面AVC一样,loadNibNamed时会依次调用BView的initWithCoder,awakeFromNib。还有view controller所没有的layoutSubviews。

然后测试发现
1. 对于bview的子控件,都得在awakeFromNib或者layoutSubviews里设置其属性才能生效,在initWithCoder是不行的。这篇文章也说了。
2. self.frame必须在layoutSubviews里设置才能生效!!
3. initWithCoder,awakeFromNib里设置显示的效果都不准确。网上有人说是因为还没加载完。且如上段代码所注释,直接[bv setFrame: CGRectMake(10, 10, 100, 100)]也没有用。

代码:

BView.m

- (id)initWithCoder:(NSCoder *)aDecoder{    self = [super initWithCoder:aDecoder];    if (self) {        NSLog(@"BView-------initWithCoder----------called");    }    return self;}-(void)awakeFromNib{     NSLog(@"BView-------awakeFromNib----------called");    self.bviewLabel.text = @"b商品";    self.bviewLabel.backgroundColor = [UIColor purpleColor];    self.bviewLabel.frame = CGRectMake(5, 10, 50, 30);//当不用autolayout的时候代码设置self.bviewLabel.frame是生效的    self.backgroundColor = [UIColor greenColor];//    self.frame = CGRectMake(10, 10, 300, 200);}-(void)layoutSubviews{    NSLog(@"BView-------layoutSubviews----------called");     self.frame = CGRectMake(10, 10, 300, 200);//此句必须写这个方法里}

——————————我是分割线———————————————-

下面看看直接alloc生成此view对象会调用哪些方法:

当不在外设置view的frame时,也不在initWithFrame,init里设置frame时:

    CView *cv = [[CView alloc]init];    [self.view addSubview:cv];

打印显示先后走了initWithFrame,init方法

当在initWithFrame或者init里或者外部cv setFrame时,会触发layoutSubviews。
打印显示先后走了initWithFrame,init,layoutSubviews方法

init里的setFrame会覆盖initWithFrame里的,layoutSubviews里如果写了setFrame则会覆盖init里的。

-(instancetype)initWithFrame:(CGRect)frame{    if (self = [super initWithFrame:frame]) {        NSLog(@"CView-------initWithFrame----------called");     self.frame = CGRectMake(0, 0, 40, 40);     self.backgroundColor = [UIColor greenColor];    UILabel * clableview = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 10, 10)];    clableview.text = @"c商品";    clableview.backgroundColor = [UIColor purpleColor];    [self addSubview:clableview];      }    return self;}- (instancetype)init{    if (self = [super init]) {        NSLog(@"CView-------init----------called");     // self.frame = CGRectMake(10, 10, 20, 80);    }    return self;}-(void)layoutSubviews{    NSLog(@"CView-------layoutSubviews----------called");    // self.frame = CGRectMake(10, 10, 80, 20);}

当使用 CView *cv = [[CView alloc]initWithFrame:CGRectMake(10, 10, 10, 10)];
会调用initWithFrame和layoutSubviews不会调用init方法。

所以可以直接在initWithFrame里面去设置frame backgroundcolor subview等。

0 0