一个既可以通过编程实例化,也可以在IB中实例化的视图控制器?

3
一个视图控制器FooViewController在创建时需要进行一些初始化(针对它本身而不是托管的视图-甚至在视图加载之前)。我希望能够以两种方式创建它:1.以编程方式,可能带有一些参数。2.在Interface Builder中。对于(1),我会像这样编写初始化程序:(以下省略)当在Interface Builder中创建时,我希望最终结果与使用无参数的init初始化对象相同。现在如果我只是这样做:- (id)initWithCoder:(NSCoder *)decoder{return [self init];}则会忽略在Interface Builder中设置的titlewantsFullScreenLayoutnibName属性,但这没关系。nibName在init中硬编码,并且在任何情况下都可以通过编程方式实例化控制器,因此在那里设置title。问题在于parentViewController没有被设置(默认的initWithCoder:会根据NIB中的对象层次结构设置它)。我该如何从nib中获取父对象?然后我将initWithCoder:更改为类似于:(以下省略)或者我应该使用一些不同的方法来创建既可以通过编程方式实例化又可以在IB中实例化的控制器吗?
2个回答

0

不要试图制作一个既可以使用nib,又可以不使用nib的视图控制器。这将是一场噩梦,因为nib加载使用了一些正常入口点并提供了新的入口点,而且它会对操作系统版本变化非常脆弱。

你可以做的是让视图控制器始终从nib中加载,然后给自己一个方便的初始化程序来通过nib进行操作:

- (id) init {
  return [[[self class] alloc] initWithNibNamed:@"MyNibName" bundle:nil];
}

然后您可以以正常方式通过其他nib引用它,并在不想显式处理nib时调用方便的init方法。

[self class] 应该只是 self 吗?如果是这样的话,你实际上并没有从 NIB 中加载视图控制器。UIViewController 的 nibName 属性是其视图的 NIB,而不是控制器本身。我认为为每个控制器准备两个 NIB(一个用于自身,一个用于视图)不是正确的方法... :/ - Jaka Jančar
它是固定的,应该是[[self class] alloc],因为我不知道你的类是什么。为了做我建议的事情,你需要将文件所有者设置为你的类。initWithNibNamed所做的是初始化视图控制器,然后将所有连接绑定到刚刚初始化的VC中的nib。看起来你正在尝试在nib中创建一个单独的视图控制器对象,你如何设置你的文件所有者,我认为你正在与系统作斗争。 - Louis Gerbarg
啊,我觉得你误解了问题...视图控制器将始终使用一个nib来创建它自己的视图。我总是在IB中构建视图。区别在于控制器对象是以编程方式还是在nib中创建。 - Jaka Jančar
好的,我想我明白你想做什么,但你不能用你现在的方法实现它。你应该设置一个IBOutlet,让nib可以将其设置为父级,然后在nib中连接它,这样它就会为你设置好了。唯一的问题是你需要在initWithCoder:中调用[super initWithCoder:]。initWithCoder:也是一个指定的初始化程序,通过非编码器的初始化程序可能会破坏nib试图设置的连接。 - Louis Gerbarg

0
为什么不在viewDidLoad中进行初始化操作 - 当在IB之外创建时,您可以在初始化之后但在viewDidLoad被调用之前使用其他方法或属性设置初始值。

1
因为viewDidLoad是用于视图初始化而不是控制器初始化的。例如,在低内存情况下释放视图时,它可以被多次调用。显然,控制器初始化应该在init中完成。 - Jaka Jančar
在viewDidLoad中执行初始化之前,您可以检查是否已经完成了初始化。 由于您显然无法从IB实例化的视图控制器中传递自定义参数以进行初始设置,因此您需要一个在IB初始化和标准创建的情况下都会被调用的地方,并具有传递参数的选项(根据提出的原始问题)。viewDidLoad是这个过程的一个很好的候选者,因为您还将做特定于视图的初始化。否则,您将使用许多不同的init方法来混淆自己。 - Kendall Helmstetter Gelner
1
此外,使用viewDidLoad可以让您在视图实际加载之前通过属性设置一些参数来初始化视图控制器。 - Kendall Helmstetter Gelner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接