【问题标题】:Loading a nib file inside a UIViewController在 UIViewController 中加载 nib 文件
【发布时间】:2013-03-27 12:56:02
【问题描述】:

我正在试验如何将 nib 文件加载到 UIViewController。

我创建了一个单独的 nib 文件,名为 Email。首先我注意到当视图控制器被加载时,initWithNibName 方法没有被调用。所以我像这样从viewDidLoad 方法手动调用它,

[self initWithNibName:@"Email" bundle:[NSBundle mainBundle]];

它没有工作。我还收到一条警告说未使用表达式结果。

我在网上搜索,偶然发现了this 的文章,并实现了loadView 方法,如下所述,

- (void)loadView
{
    [super loadView];

    UINib *nib = [UINib nibWithNibName:@"Email" bundle:nil];
    [nib instantiateWithOwner:self options:nil];
}

方法被调用但视图控制器仍然是空的!

谁能告诉我我在这里忽略了什么以及如何做到这一点?

谢谢。

更新:

首先,感谢所有回复。然而 voromax 和 svena 的回答建议我应该删除 segues 并自动加载我不太喜欢的笔尖。 Anil 的答案很有效,现在我还有最后一个障碍要跳过。

我有多个 nib 文件。根据用户的选择,它应该加载一个特定的笔尖。所以我尝试的是,像这样将所有笔尖放入数组中,

- (void)loadView
{
    [super loadView];

    NSArray *nibs = [[NSArray alloc] initWithObjects:
                     [[NSBundle mainBundle] loadNibNamed:@"Facsimile" owner:self options:nil],
                     [[NSBundle mainBundle] loadNibNamed:@"Email" owner:self options:nil],
                     [[NSBundle mainBundle] loadNibNamed:@"Memorandum" owner:self options:nil],
                     [[NSBundle mainBundle] loadNibNamed:@"ProjectMemo" owner:self options:nil], nil];


    self.view = [nibs objectAtIndex:0];
}

并使用它的索引来访问它,例如self.view = [nibs objectAtIndex:1];。但它会抛出一个错误 *Terminating app due to unaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM _setViewDelegate:]: unrecognized selector sent to instance 0xd56fd20'*

为什么会出现这个错误?如果不可能,我愿意接受建议。

再次感谢。抱歉有点拖了后腿。

【问题讨论】:

  • 你仍然没有在你的问题中提到故事板和自定义逻辑,不是每个人都会阅读所有的 cmets... 查看更新的答案

标签: ios uiviewcontroller xib nib


【解决方案1】:

您不应该从视图控制器的方法中为视图控制器加载 nib。

如果你想从 nib 实例化一个视图控制器,你可以在那个视图控制器之外进行,通常是呈现它的视图控制器。

如果您正在呈现的视图控制器中寻找已经设置出口连接的钩子,则覆盖-awakeFromNib 是一种流行的选择。 -viewDidLoad 是另一个。

更新 #1

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
   if ( /*do your segue identification stuff*/ ) {
      UIViewController *myViewController = /*init your view controller here*/
      UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:myViewController];
      [self presentViewController:navigationController animated:YES completion:nil];
      return NO;
   }
   return YES;
}

【讨论】:

  • 有一个 UITableViewController 作为之前的视图控制器,所以我尝试在 segue 发生之前实例化它时加载 nib。 NewMailViewController *newMailVC = [[NewMailViewController alloc] initWithNibName:@"Email" bundle:nil]; newMailVC = [segue destinationViewController]; 但是没用。
  • 从您的评论中我断定您正在使用情节提要。故事板为您实例化您的视图控制器,您无需自己加载这些 nib。您是否有理由希望从使用情节提要返回从 nib 加载?
  • 是的,我正在使用 Storyboard。抱歉,我应该在问题中提到这一点。场景是这样的。我正在创建一个自定义邮件应用程序,并且有多种邮件类型。对于每种邮件类型,用户界面都不同。所以我所做的是,为每种邮件类型创建一个单独的 nib,有一个 UITableViewController 来列出邮件类型,当它继续时,根据用户的选择,它将特定的 nib 文件加载到 UIViewController。
  • 也许不是“最漂亮”的解决方案,但是是的,您必须取消 segue(如@voromax 建议的那样),然后手动从 nib 实例化。但不仅要实例化,还要将其推入导航堆栈或呈现。 init 本身是不够的,
  • @Isuru 在您的情况下,最好在一个故事板中创建所有视图控制器,跳过硬 segue 绑定并使用 segue 实例的 instantiateViewControllerWithIdentifier: 方法来获取适当的视图控制器并手动呈现
【解决方案2】:

您应该使用 nib 文件来实例化视图控制器本身。 e.

UIViewController *ctrl = [[UIViewController alloc] initWithNibName:@"Email" bundle:nil];

之后你就可以展示这个控制器了

更新

如果您需要选择应用程序逻辑应该加载哪个视图控制器,最好在一个情节提要中创建所有视图控制器,跳过硬 segue 绑定并使用情节提要实例的instantiateViewControllerWithIdentifier: 方法来获取适当的视图控制器并手动呈现。我假设您的表格视图控制器已经在导航控制器中:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    if (APPROPRIATE_INDEX_PATH) {
        UIViewController *ctrl = [self.storyboard instantiateViewControllerWithIdentifier:IDENTIFIER];
        [self.navigationController pushViewController:ctrl animated:YES];
    }
}

【讨论】:

  • 有一个 UITableViewController 作为之前的视图控制器,所以我尝试在 segue 发生之前实例化它时加载 nib。 NewMailViewController *newMailVC = [[NewMailViewController alloc] initWithNibName:@"Email" bundle:nil]; newMailVC = [segue destinationViewController]; 但是没用。
  • 你可以通过– shouldPerformSegueWithIdentifier:sender:返回NO来取消这个segue并手动加载你的控制器
【解决方案3】:

使用以下代码从 nib 加载视图并用作视图控制器的视图

- (void)loadView
{ 
[super loadView];

NSArray *nib =[[NSBundle mainBundle]loadNibNamed:@"test" owner:self options:nil];
self.view = [nib objectAtIndex:0];
}  

编辑

根据用户选择加载单个笔尖。查看加载单个笔尖

    NSArray *nib =[[NSBundle mainBundle]loadNibNamed:@"test" owner:self options:nil];  

将返回一个对象数组。从您更新的问题中,我可以看到您将这些数组存储到另一个数组中。现在你的 nib 数组是一个 'array' 对象的数组。

 self.view = [[nibs objectAtIndex:0]objectAtIndex:0]; 

会起作用。

但是不好,根据用户选择加载单个笔尖

【讨论】:

  • 感谢您的回复。这种方法有效,我有一个附带问题。我有多个笔尖文件。根据用户的选择,它应该加载一个特定的笔尖。所以我尝试的是,将所有笔尖放在数组中,如this,并使用它的索引来访问它self.view = [nibs objectAtIndex:1];。但是它会抛出一个错误Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM _setViewDelegate:]: unrecognized selector sent to instance 0xd56fd20' 我是遗漏了什么还是有其他方法可以走关于它?
  • 你能把你的代码和问题一起发布吗?我无法访问该页面。实际上 loadNib 返回的 nib 数组不仅包含 view ,它还包含 nib(buttons/ label..) objectAtIndex[0] 中的所有控件(很可能是查看每个笔尖是否有单个视图)。没有看到你的代码我不能说确切的问题
  • @Isuru 从笔尖获取视图的好解决方案。但是子视图绑定会发生什么?
  • @voromax 如果您正在加载 nib 以获取视图,则该视图应该是自定义视图。您必须绑定到自定义类而不是文件所有者(视图控制器)。然后通信 b/w 视图和控制器使用委托。这是当视图控制器可以处理多个视图时使用的解决方案,视图可能会根据某些条件(iphone/ipad)而有所不同。我不喜欢这种方法,因为它很复杂。否则,每个视图的单独视图控制器会更好。但是 OP 真的想要这个,他可以使用这个解决方案
  • @Anil 感谢您的澄清。
猜你喜欢
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 2015-01-21
  • 1970-01-01
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多