initWithNibName 调用了两次或加载了错误的 xib

Posted

技术标签:

【中文标题】initWithNibName 调用了两次或加载了错误的 xib【英文标题】:initWithNibName either called twice or wrong xib loaded 【发布时间】:2012-05-31 13:51:08 【问题描述】:

我正在编写一个 Cocoa 应用程序,并希望该应用程序作为一种向导工作。因此,在主窗口中,我有一个自定义视图,它与用户交互,并在用户逐步完成向导的各个阶段时从登录屏幕更改为设备激活屏幕。我目前已经覆盖了 WizardViewController 的 awakeFromNib 方法:

- (void)awakeFromNib
   //If no redirect request save, add first view: ID Login
   NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
   NSString *tokenRequest = [defaults objectForKey:@"redirectRequestToken"];
   if (!tokenRequest)
       SignInWithIDViewController *signInViewController = [[SignInWithIDViewController alloc] initWithNibName:@"SignInWithIDViewController" bundle:nil];
       [wizardView addSubview:[signInViewController view]];
    else 
    NSLog(@"Have already logged in.");
   

照原样,SignInIDViewController 中的 initWithNibName 被调用了两次,一次是由我显式调用,另一次是在加载视图时(可能是通过 loadView)。但是,如果我只是调用 init,那么 initWithNib 名称只会调用一次,但会加载错误的 xib 文件(属于 DeviceActivationViewController 类)。我似乎无法弄清楚我做错了什么,因为 signInViewController 不应该被初始化两次,但我需要在 IB 中显示正确的 xib 文件。

我目前在这个类中唯一不是用户界面 IBAction 的方法是生成的 initWithNibName 方法加上添加的 NSLog 语句。

【问题讨论】:

你怎么知道initWithNibName被调用了两次?你看到了什么结果? 当你生成一个新的NSViewController子类时,会自动生成initWithNibName,代码如下:code- (id)initWithNibName:(NSString *)nibNameOrNil bundle: (NSBundle *)nibBundleOrNil self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) // 这里的初始化代码。 返回自我;所以我添加了一个 NSLog 来跟踪它。这也会影响其他方法的功能——也就是说,我的 awakeFromNib 在两个不同的实例中被调用两次,我知道这是因为每个实例在不同的端口上打开一个服务器。 只是为了澄清最后一句话:我的 awakeFromNib 从每个实例中调用一次。总共两个。 从您发布的信息中很难判断为什么会发生这种情况。我做了一个小测试应用程序,它从应用程序委托中分配 initWithNibName 的向导控制器(将主窗口的内容视图设置为向导控制器的视图),然后将您在上面发布的代码放入向导控制器的 initWithNibName 或 awakeFromNib 方法中,并且我没有看到 SignInViewController 初始化了两次。除了使用您需要的任何子视图填充自定义视图之外,您是否在 xib 文件中做了其他任何事情? 我意识到很难准确理解我在说什么,但是有 4 个以上的类,我不想把所有的代码都放上去。不过,感谢您查看并尝试一下。目前,我的 MainMenu.xib 中没有任何内容,默认为包含窗口、自定义视图和下一步按钮的 WizardViewController。 (这个 initWithNibName 只被调用一次。)SignInWithIDViewController.xib 有一个 WebView 和一个自定义视图上的按钮。 【参考方案1】:

我认为在 IB(蓝色立方体)中创建对象并在代码中实例化它们是问题所在。如果您在 IB 中为它们创建了对象,那么它们将在 awakeFromNib 中实例化,您也不应该在代码中对它们调用 alloc init ——这将创建一个新实例。

我没有太多在 OSX 中使用视图控制器的经验,但您似乎无法将 IBActions 连接到视图控制器(作为文件的所有者)。我使它工作的方式是子类化自定义视图(当您添加视图控制器时为您创建),将该视图的类更改为您的新子类,并将操作方法​​放入该类中。看起来这应该由视图控制器处理,但我认为它不起作用与视图控制器不在 OSX 的响应者链中有关(而我认为它在 ios 中)。

编辑后:在绕过内存管理问题后,我想我找到了最好的方法。您可以并且可能应该(以符合 Apple 的 MVC 范例)将按钮方法放在视图控制器类中,而不是像我上面所说的那样放在视图中。您实际上可以将 IBActions 连接到视图控制器(作为文件的所有者),您只需要确保在代码中实例化它时保留视图控制器。为此,您需要在要在其中实例化 SignInViewController 类的任何类中将 signInViewController 设为属性,并在属性声明中使用“retain”。那么您就不需要(也不应该)在 IB 中创建任何蓝色立方体。

【讨论】:

谢谢!我花了一点时间,但我已经消除了使用您的响应调用了两次 initWithNibName,但现在 SignInWithIDViewController 中基本上没有任何内容(除了 init 和 dealloc)——这似乎是对空间的巨大浪费。有什么办法可以消除 SignInWithIDViewController 并只使用 NSView 子类? @Katie,我认为您应该使用视图控制器,但将 IBActions 放在那里 - 有关详细信息,请参阅我编辑的答案。 是的,这似乎有效。我认为这真的就像确保 xib 文件的所有者是相应的视图控制器类一样简单。谢谢!

以上是关于initWithNibName 调用了两次或加载了错误的 xib的主要内容,如果未能解决你的问题,请参考以下文章

OnLoadFinished() 调用了两次

为啥我的 UIViewController 被加载了两次? IOS 7

prepareForSegue 调用了两次

为啥 ngAfterContentInit 钩子被调用两次?

nextjs 自定义响应检测钩子调用了两次

Page_Load 在 ASP.NET 页面中触发了两次