UI控件初始化問(wèn)題:initWithFrame和initWithCoder、aweakFromNib的執(zhí)行

UI控件初始化問(wèn)題:initWithFrame和initWithCoder、aweakFromNib的執(zhí)行

在iOS學(xué)習(xí)和程序開(kāi)發(fā)過(guò)程中,我們經(jīng)常會(huì)遇到一些自定義UI控件或控制器在初始化時(shí)出現(xiàn)問(wèn)題,尤其在大家剛開(kāi)始接觸時(shí),幾種初始化方法的作用以及調(diào)用的時(shí)機(jī)往往容易混淆,這也跟我們對(duì)iOS程序設(shè)計(jì)中,類(lèi)的創(chuàng)建和實(shí)例化的過(guò)程了解不透徹有關(guān)系。本文用一些小例子來(lái)簡(jiǎn)單梳理一下幾者的關(guān)系,后面再陸續(xù)討論一些復(fù)雜情況的深入對(duì)比。

問(wèn)題:一、什么時(shí)候用initWithFrame,什么時(shí)候用aweakFromNib、initWithCoder

?二、在初始化時(shí)控件自身的frame何時(shí)能獲得?layoutSubViews何時(shí)調(diào)用


首先,我們實(shí)例化一個(gè)(控件類(lèi)型)對(duì)象可以有多種方式:

(1)純代碼創(chuàng)建。創(chuàng)建自定義的UI控件類(lèi),然后實(shí)例化該類(lèi)型的對(duì)象。

(2)通過(guò)IB(Interface Builder)創(chuàng)建,就是俗稱(chēng)的“拖線”。當(dāng)我們創(chuàng)建好xib文件的時(shí)候,就相當(dāng)于創(chuàng)建好了控件類(lèi),但是如果不實(shí)例化,也是沒(méi)有用的,所以需要加載,這里用loadNibName來(lái)加載(實(shí)例化)UI控件。

1、搭建實(shí)驗(yàn)環(huán)境A,代碼創(chuàng)建控件(TestCodeingView繼承自UIView)

-(void)loadFromCoding

{

? ? TestCodeingView * viewCoding = [[TestCodeingView alloc]init];

? ? viewCoding.frame=CGRectMake(100,100,200,200);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? viewCoding.backgroundColor=[UIColor greenColor];

? ? [self.view addSubview:viewCoding];

}

在TestCodeingView類(lèi)中對(duì)以下方法進(jìn)行重寫(xiě)-(instancetype)init

{

? ? self=[super init];

? ? NSLog(@" init =====> 執(zhí)行了");

? ? NSLog(@"此時(shí)view的frame====》 %@",NSStringFromCGRect(self.frame));

? ? return self;


}-(instancetype)initWithFrame:(CGRect)frame

{

? ? self=[super initWithFrame:frame];

? ? NSLog(@" initWithFrame =====> 執(zhí)行了");

? ? NSLog(@"此時(shí)view的frame====》 %@",NSStringFromCGRect(self.frame));

? ? return self;

}-(instancetype)initWithCoder:(NSCoder *)aDecoder

{

? ? self=[super initWithCoder:aDecoder];?

? ? NSLog(@" initWithCoder =====> 執(zhí)行了");

? ? return self;

}-(void)awakeFromNib

{

? ? NSLog(@" awakeFromNib =====> 執(zhí)行了");

}-(void)layoutSubviews

{

? NSLog(@" layoutSubviews =====> 執(zhí)行了");

? NSLog(@"此時(shí)view的frame====》 %@",NSStringFromCGRect(self.frame));

}

運(yùn)行結(jié)果:


然后更改部分代碼:

-(instancetype)initWithFrame:(CGRect)frame

{

? ? self=[super initWithFrame:frame];

? ? NSLog(@" initWithFrame =====> 執(zhí)行了");

? ? NSLog(@"此時(shí)view的frame====》 %@",NSStringFromCGRect(self.frame));

? ? UILabel * label = [[UILabel alloc]init];

? ? label.text=@"我是新建的label";

? ? label.backgroundColor=[UIColor orangeColor];

? ? self.label=label;

? ? [self addSubview:label];


? ? return self;?

}-(void)layoutSubviews

{

? ? NSLog(@" layoutSubviews =====> 執(zhí)行了");?

? ? NSLog(@"此時(shí)view的frame====》 %@",NSStringFromCGRect(self.frame));

? ? self.label.frame = CGRectMake((self.frame.size.width-150)/2,self.frame.size.height/2,150,30);


}

運(yùn)行結(jié)果:


小結(jié)一下:(1)純代碼創(chuàng)建的UI控件不執(zhí)行aweakFromNib方法和 initWithCoder方法。

     (2)layoutSubciews方法在控件初始化完成后(自身和子控件的實(shí)例化結(jié)束)調(diào)用,方法中能獲得到當(dāng)前控件的frame,以便于給子控件布局。如有子控件,調(diào)用兩次。

    ?。?)系統(tǒng)在調(diào)用以上方法時(shí),有著特定的先后順序。



2、搭建實(shí)驗(yàn)環(huán)境B,Xib創(chuàng)建控件


通過(guò)xib加載自定義UI控件,如下圖,TestXibView類(lèi)為手動(dòng)創(chuàng)建的UI控件類(lèi),繼承自UIView


-(void)loadFromXib

{

? ? TestXibView * viewXib = [[[NSBundle mainBundle]loadNibNamed:@"testXibView" owner:nil options:nil] lastObject];?

? ? viewXib.center=self.view.center;

? ? [self.view addSubview:viewXib];

}



在TestCodeingView類(lèi)中對(duì)以下方法進(jìn)行重寫(xiě)


-(instancetype)init

{

? ? self=[super init];

? ? NSLog(@" init =====> 執(zhí)行了");? ?

? ? return self;

}-(instancetype)initWithFrame:(CGRect)frame

{

? ? self=[super initWithFrame:frame];?

? ? NSLog(@" initWithFrame =====> 執(zhí)行了");


? ? return self;


}-(instancetype)initWithCoder:(NSCoder *)aDecoder

{

? ? self=[super initWithCoder:aDecoder];?

? ? NSLog(@" initWithCoder =====> 執(zhí)行了");

? ? return self;

}-(void)awakeFromNib

{

? ? NSLog(@" awakeFromNib =====> 執(zhí)行了");?

}-(void)layoutSubviews

{

? ? NSLog(@" layoutSubviews =====> 執(zhí)行了");

}

運(yùn)行結(jié)果:


更改部分代碼,對(duì)Xib加載的控件使用代碼進(jìn)行修改 (添加了一個(gè)子控件和更改背景顏色):

-(instancetype)initWithCoder:(NSCoder *)aDecoder

{

? ? self=[super initWithCoder:aDecoder];


? ? NSLog(@" initWithCoder =====> 執(zhí)行了");


? ? UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(0,0,150,30)];

? ? label.text=@"我是新建的label";

? ? label.backgroundColor=[UIColor orangeColor];

? ? label.center=CGPointMake(self.center.x, self.frame.size.height-30);

? ? [self addSubview:label];


? ? return self;

}-(void)awakeFromNib

{

? NSLog(@" awakeFromNib =====> 執(zhí)行了");

? self.backgroundColor=[UIColor yellowColor];


}


運(yùn)行結(jié)果:


小結(jié)一下:(1)通過(guò)Xib創(chuàng)建UI控件,不會(huì)調(diào)用init和initwith方法。

?(2)創(chuàng)建一個(gè)控件類(lèi),和xib關(guān)聯(lián),是可以修改Xib中的屬性的。

?(3)一樣會(huì)調(diào)用layoutSubViews方法

(4)因?yàn)橥ㄟ^(guò)拖線和配置,已經(jīng)固定了控件的大小和布局,所以frame可以獲得

(5)initWithCoder和 aweakFromNib 在這里作用相同,都被系統(tǒng)調(diào)用


總結(jié)及延伸:

當(dāng)我們弄清楚控制器加載的各種情況后,相對(duì)于用代碼,使用IB和xib文件來(lái)組織UI,可以省下大量代碼和時(shí)間,從而得到更快的開(kāi)發(fā)速度;同時(shí),Xib最大的問(wèn)題在于其設(shè)置往往并非最終設(shè)置,在代碼中你將有機(jī)會(huì)覆蓋你在xib文件中進(jìn)行的UI設(shè)計(jì),造成錯(cuò)誤和混亂。


說(shuō)了好多,總結(jié)一下也無(wú)非幾句話:

1、用Xib創(chuàng)建控件,對(duì)于控件的后續(xù)操作都寫(xiě)在initWithCoder或aweakFromNib方法中;

2、純代碼寫(xiě)創(chuàng)建的控件,對(duì)于控件的后續(xù)操作都寫(xiě)在initWithFrame方法中;

3、添加子控件時(shí),注意布局(frame的獲得),合理靈活的使用xib加載控件;

4、至于initWithCoder和aweakFromNib的區(qū)別在后面再做討論(關(guān)于通過(guò)xib加載控制器)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容