initWithNibName导致的初始化问题

众所周知,IB在加载nib的过程中存在着一些undocument行为,有的行为确实是不可理喻的,因此程序员对IB产生了抗拒心理。

今天我们要介绍的是IB导致的一个奇特行为。通过本文的描述, 作者完美地展示了IB给面向对象所带来的破坏作用。

我们有两个View
Controller,暂名为superclass和subclass。subclass继承了superclass。在superclass的initWithNibName初始化方法中,我们这样写道:

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

[self setWords:@”somebody is
knocking”];

}

return self;

在superclass的viewDidLoad方法中,我们这样写:

[super viewDidLoad];

NSLog(@"get XXX:%@", [self words]);

然后我们用subclass继承superclass。在initWithNibName方法中,我们写入:

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {[

[self setWords:@” pleaseanswer the
door”];

}

很显然,我们通过覆盖initWithNibName方法,修改了从superclass继承来的words属性。如果我们想打印pleaseanswer the
door这段文本,你可能会想重用superclass的viewDidLoad方法:

- (void)viewDidLoad{

[super viewDidLoad];

}

好了,运行程序。在加载superclass.xib时,控制台将打印somebodyis
knocking。而加载subclass.xib时,控制台会打印please answer the door。

Hey,等一等。为什么我会在两个ViewController中都看到了somebody is knocking?

不用看了,subclass对象的words属性确实是pleaseanswer the
door。如果你正在调试代码,那么可以debug区中确认这一点。

问题在于subclass的初始化出现了问题。看这一句:self=[superinitWithNibName:nibNameOrNil
bundle:nibBundleOrNil];

这句代码将导致IB加载nib文件,并立即调用viewDidLoad方法。我们可以看到在初始化subclass时的调用顺序如下:

1. subclass->initWithNibName

2. superclass->initWithNibName

3. superclass->setWords

4. subclass->viewDidLoad

5. superclass->initWithNibName

6. subclass->setProperty

让我再解释一下:

1. 首先subclass的initWithNIbName方法调用。

2. 接着调用superclass的initWithNibName方法。

3. 在superclass的initWithNibName方法中,words属性被设置为somebodyis knoking。

4. superclass的initWithNibName方法结束,表示nib文件已加载,则调用nib文件的File’sowner所指向的
viewDidLoad方法。注意,这时的nib文件名应为subclass.nib,于是应调用[subclass viewDidLoad]方法。

5.
subclass的viewDidLoad方法又调用了supclass的viewDidLoad方法。于是控制台打印出的是words属性的当前值somebodyis
knoking。

6. 最后才是initWithNibName方法剩余的代码,在这里我们将words属性修改为pleaseanswer the
door。但为时已晚,在此之前viewDidLoad已经执行结束。

解决的办法是简单的,不要在initWithName方法中修改从父类继承来的属性,相反,我们可以在[super iewDidLoad]之前这样做:

- (void)viewDidLoad{

[selfsetWords:@” pleaseanswer the door”];

[super viewDidLoad];

}

结论

由于initWithNibName或者是IB
这些限制,.nib文件违反了面向对象的原则。.nib文件无法从另一个.nib文件继承。不管你的类如何继承,但nib文件中不会保存类的层次结构,File’sowner也无法指向类链。

initWithNibName导致的初始化问题,布布扣,bubuko.com

时间: 2024-10-25 15:33:09

initWithNibName导致的初始化问题的相关文章

Tomcat启动时项目重复加载,导致资源初始化两次的问题

最近在项目开发测试的时候,发现Tomcat启动时项目重复加载,导致资源初始化两次的问题 导致该问题的原因: 如下图:在Eclipse中将Server Locations设置为"Use Tomcat installation(takes control of Tomcat installation)"时, 就会导致该问题! 根本原因: 解决方法一: 把server.xml中的context删除掉 但这会导致一个问题: 在Web Modules中你将看不到我们的项目 解决方法二: 在Tom

验证当多个类之间有继承关系时,创建子类对象会导致父类初始化块的执行。

结果:当多个类之间有继承关系时,创建子类对象会导致父类初始化块的执行.

srping mvc 集成CXF 导致类初始化两遍

cxf依赖于spring的ContextLoaderListener,而spring mvc 则依赖于DispatcherServlet. 初始化DispatcherServlet的时候会依赖初始化一个spring 容器,此容器为spring全局容器WebApplicationContext的子容器,如果调用相同的配置文件初始化将导致所有类初始化两次,造成不确定的错误. spring的字容器可以访问父容器内的对象,既然如此,可以让全局容器加载除Controller层以外的类,而让spring m

tomcat启动项目被重新加载,导致资源初始化两遍

之前没有遇到过这个问题,配了三天的项目了,惊人啊!!!各种怪问题全被我赶上了.真有种骂人的冲动. tomcat启动项目时,项目资源被加载两遍. 原因:配置虚拟目录导致,项目被重新加载. <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespa

Ojective-C:含有中文 导致NSURL初始化一直为null的解决办法

在学习Ojective-C过程中,需要读取文件中的内容,但发现指针变量url的值一直为nil. 代码如下: NSString *strUrl=@"file:///Users/fengziwu/Desktop/笔记.txt"; NSURL *url = [[NSURL alloc] initWithString:strUrl]; 后来发现原因:编码问题,带中文字符的文件路径导致,需要对路径进行编码处理 NSString类中有这两个方法: - (nullable NSString *)st

为什么通过子类引用父类静态方法不会导致子类初始化?

2014.9.2 看下边这个程序: class SuperClass { static{ System.out.println("superClass init"); } public static int value=123; public static void superMethod() { System.out.println("我是supermethod."); } } class SubClass extends SuperClass { static{

Tomcat启动时项目重复加载,导致资源初始化两次!

一.现象: 每次启动Tomcat 的时候,工程会被加载两次 二.原因: 在tomcat/conf/server.xml配置虚拟目录引起,如下配置: 我们在Host标签里配置了appBase="webapps",tomcat会去加载一次应用. 在<Context>里配置了一次docBase,tomcat会又去加载一次引用. 导致项目会加载二次. 三.解决: 去掉appBase="webapps"即可! <Host name="localho

当多个类之间有继承关系时,创建子类对象会导致父类初始化块的执行。

源代码 public class inherit { public static void main(String[] args){ first a=new first(); a.show(); } } class second{ String name; { name="zxr"; } } class first extends second{ int age=20; void show() { System.out.println("名字"+name); Sys

initWithNibName与viewDidLoad的执行关系以及顺序

转载自:http://www.java123.net/v/380331.html 一个ViewController,一般通过init或initWithNibName来加载.二者没有什么不同,init最终还是要调用initWithNibName方法(除非这个ViewController没有nib文件). 我们经常在initWithNibName方法中初始化视 一个ViewController,一般通过init或initWithNibName来加载.二者没有什么不同,init最终还是要调用initW