为什么我的awakeFromNib不会触发?

16

我开始将更多的视图层次结构构建转移到IB中。

我有一个名为"AlignmentViewController.xib"的nib文件,在其中使用AlignmentViewController作为文件所有者设置了我的视图层次结构。 这个很好运行。

我还不太清楚的方法之一是awakeFromNib。 在AlignmentViewController的以下代码片段中,我添加了单个附加方法awakeFromNib。 但是,它并没有被调用:

- (void)awakeFromNib {

   NSLog(@"AlignmentViewController - awakeFromNib");
   [super awakeFromNib];

}

- (id)initWithChromosomeName:(NSString *)chromosomeName 
               basepairStart:(NSUInteger)basepairStart 
                 basepairEnd:(NSUInteger)basepairEnd {

    self = [self initWithNibName:@"AlignmentViewController" bundle:nil];

    if (nil != self) {


        self.title          = @"Alignment";

        self.chromosomeName = chromosomeName;
        self.basepairStart  = basepairStart;
        self.basepairEnd    = basepairEnd;

        self.wantsFullScreenLayout = YES;

    }

    return self;
}

有人能为我澄清一下我错过了什么吗?

谢谢, 道格

更新: 阅读了一些答案后,我意识到我需要弄清楚一些非常基本的东西。

看看初始化:

- (id)initWithChromosomeName:(NSString *)chromosomeName 
               basepairStart:(NSUInteger)basepairStart 
                 basepairEnd:(NSUInteger)basepairEnd {

    self = [self initWithNibName:@"AlignmentViewController" bundle:nil];

我注意到我间接地调用了initWithNibName:bundle:。这是否是不良做法?AlignmentViewController.xib文件定义了我的视图层次结构。但我并没有以典型的方式使用initWithNibName:bundle:? 有更好的方法吗?


2
UIViewController还提供了viewDidLoad方法,专门用于在视图加载后(无论是手动加载还是从nib文件加载)执行控制器中的任何处理。 - Sixten Otto
是的,我经常使用viewDidLoad。我只是试图将更多的UI构建移动到IB,并且我需要在某个时候处理awakeFromNib。 - dugla
3
使用IB不强制要求使用awakeFromNib,也不与使用viewDidLoad相矛盾。 - Sixten Otto
4个回答

40

-awakeFromNib 会被发送到所有从nib实例化的对象,这些对象是在所有nib对象完成实例化之后才创建的。Owner不属于这些对象。Owner在反序列化nib之前存在,并且在加载后与nib连接,因此它不会收到-awakeFromNib消息(除非它自己被其他nib实例化)。

这里的一个线索是,-initFromChromosomePair:basepairStart:basepairEnd:-awakeFromNib两者都不可能被同时调用。nib加载器总是调用-initWithCoder:-initWithFrame:-init方法(其规则见Nib对象生命周期)。你有另外一个指定的初始化器,强烈表明你在代码中手动创建了这个对象,这意味着这个对象不是“从nib唤醒”的。


谢谢Rob,我猜我对initWithNibName:bundle:的语义不太清楚。在我的代码其他地方确实调用了initWithChromosomeName:basepairStart:basepairEnd:,并且像上面显示的那样调用了initWithNibName:bundle:。如果使用initWithNibName:bundle:会有任何nib相关方法触发吗? - dugla
4
许多代码会针对由nib加载器实例化的对象进行操作。nib的所有者不在nib中,因此不会收到-awakeFromNib消息。-viewDidLoad会发送给视图控制器,在那里您可以完成需要在nib完成加载后执行的任务。请注意,视图控制器可以在nib中,因此可以在从父nib加载时接收-awakeFromNib(当其自身的nib完成加载时)以及稍后的-viewDidLoad。-awakeFromNib会在nib中的所有对象实例化并将IBOutlet连接之后发送给所有对象。 - Rob Napier
现在我明白了。谢谢Rob,这真的澄清了一些事情。我忽略了filesOwner只是一个代理而不是nib成员的事实。太酷了。非常感谢Rob。 - dugla
很好,我没有意识到当Nib的视图是自定义类时,FileOwner不会得到这个调用。 - htafoya

35

仅作澄清:-awakeFromNib 在 Cocoa 中发送给文件的所有者,但不在 Cocoa Touch 中发送。

来自苹果公司的文档:

...

  • 它向定义匹配选择器的nib文件中的适当对象发送一个 awakeFromNib 消息:
    • 在 Mac OS X 中,该消息被发送到定义方法的任何接口对象。它还发送到文件的所有者和任何定义它的代理对象。
    • 在 iPhone OS 中,此消息仅发送给由nib加载代码实例化的接口对象。它不会发送给文件的所有者、第一响应者或任何其他代理对象。

2
根据您提供的信息,我认为我知道您的问题所在。当对象从nib文件反序列化时,会调用awakeFromNib。在这里,您有一个对象,即所有者,在nib加载之前存在。因此,awakeFromNib永远不会发送到您的AlignmentViewController.h
如果您需要在此处执行某些操作,请尝试改用loadView。或者在加载nib后执行它。您想在awakeFromNib中执行什么操作?

谢谢Gordon。我只是试图更好地理解与nib相关的代码语义和时间。我正在逐渐依赖IB进行UI构建,但我仍然不确定IB世界和XCode世界如何同步。那么,由于我使用initWithNibName:bundle:,是否会触发任何与nib相关的方法? - dugla
不,问题在于awakeFromNib没有在你的控制器上被调用,因为你的控制器不在nib文件中。它将会在nib文件中的所有视图和其他对象上被调用。 - Sixten Otto
1
请注意在Gordon说“loadView”上面的地方,我相信他指的是“viewDidLoad”。当处理基于nib的视图控制器时,通常不应该对-loadView进行修改。 - Rob Napier
Sixten和Rob非常有帮助。雾气正在消散,启蒙即将来临。干杯! - dugla

-2

你应该重写 func awakeFromNib()。

不要重写 class func awakeFromNib()。

override func awakeFromNib() {
    super.awakeFromNib()
    setupContent()
}

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