如何创建一个具有多个 ViewController 可以使用的关联视图类的 Nib

Posted

技术标签:

【中文标题】如何创建一个具有多个 ViewController 可以使用的关联视图类的 Nib【英文标题】:How can I Create a Nib with an associated View Class that can be used by Multiple ViewControllers 【发布时间】:2010-01-14 18:30:04 【问题描述】:

我要提出一个新问题来跟进我的上一个问题 (superview and parentviewcontroller nil after adding a subview)。基本上我知道使用子视图是一个好主意,但是我不应该有一个 ViewController 来控制一个存在于另一个 ViewController 中的子视图。基本上我想做以下... 我有两个 ViewControllers 共享一个公共子视图。我已经将该子视图创建为一个名为 SearchDate.xib 的 nib。文件所有者是相应的类 SearchDateView.m/h。该类在笔尖中的 UIView 内有一个唯一元素的出口,它是一个标签。 SearchDateView 类还具有更改 SearchDateView.xib 中标签值的功能。我希望我的两个 ViewController 都加载这个笔尖,但显然我不知道如何正确加载笔尖。无论我做什么,充其量都没有显示,最坏的情况是抛出异常。苹果文档谈到将 IB 中的其他类实例拖入您的主视图,但这似乎没有奏效。我的 ViewController 中有一个 SearchDateView 插座,我尝试在控制器的加载视图上执行此操作:

searchDateView = [[[NSBundle mainBundle] loadNibNamed:@"SearchDateView" owner:self options:nil] objectAtIndex:0];
[[self view] addSubview:searchDateView];

但我得到了这个例外:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MainViewController 0x431fac0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key searchDateLabel.'

我知道我在做一些完全错误的事情,但是拥有一个 nib 的正确方法是什么,关联的视图类会更新该 nib 中的一些对象,并在不同的控制器中重用该 nib?

编辑:鉴于评论可能还不够清楚。我不想对整个视图使用相同的 nib 文件 - 而不是子视图。因此,例如控制器 A 有一个地图和一个 SearchDateView,控制器 B 有一个表视图和一个 SearchDateView。所以我想知道如何将子视图加载到多个控制器中......

【问题讨论】:

【参考方案1】:

当使用 initWithNibName:bundle: 初始化每个控制器时,为多个控制器使用相同的 NIB 文件应该没有问题。不过,您通常不会从控制器中加载控制器自己的 nib 文件。

如果你使用 loadNibNamed::: 加载一个 nib 文件,那么你会得到一个 NSArray ,其中定义了对象,所以你不能直接将它用作视图。获得视图的一种方法是使用 for() 或其他方法搜索数组以找到您想要的对象,但如果您设置 owner:self 那么它应该连接到连接到 self 中的 File's Owner 的插座,因为 File's Owner 将是 self .但是在这种情况下你可以丢弃返回值;您不需要返回的数组。如果您连接了该插座,那可能是您的主要问题(用阵列破坏插座)。

可以使用 loadNibNamed 来加载特定的视图对象(假设您从返回的数组中选择它),然后以某种方式显示它,但在控制器上使用 initWithNibName 通常更容易(在这种情况下,文件的所有者将是控制器)。

哦,您还可以在 Interface Builder 中为控制器设置 nib 文件。对多个控制器使用相同的 nib 应该没有问题,因为基本上你只是告诉 Interface Builder 设置 nib 文件来执行类似 initWithNibNamed 的操作。单击控制器对象并检查检查器窗口。

更新

我可能会这样做是为了在多个控制器中只使用一个视图:

    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"FooView" 
                                                 owner:self options:nil];
    for (id obj in nib)
        if ([obj isKindOfClass:[FooView class]])
            myNewView = (FooView *)obj;

(从 Beginning iPhone 3 Development 的示例代码中的第 8 章:单元格 2 中窃取。)

您可以在 IB 中使用 outlet 来执行此操作,在这种情况下,您可以省略 for 循环,但您可能需要为两个控制器声明 outlet 的超类,并告诉 Interface Builder File's Owner 是一个实例那个超类,所以它知道插座。可能不值得麻烦。

【讨论】:

抱歉,我可能不太清楚。我不想为整个视图使用相同的 nib 文件 - 而不是子视图。因此,例如控制器 A 有一个地图和一个 SearchDateView,控制器 B 有一个表视图和一个 SearchDateView。所以我想知道如何将子视图加载到多个控制器中。 是的,超类似乎是解决我的问题的唯一“真正”解决方案。稍后我可能会重构,但现在我找到了一些解决方法 - 谢谢!【参考方案2】:

我的 ViewController 中有一个 SearchDateView 插座,我尝试在控制器的加载视图上执行此操作:

searchDateView = [[[NSBundle mainBundle] loadNibNamed:@"SearchDateView" owner:self options:nil] objectAtIndex:0];
[[self view] addSubview:searchDateView];

但我得到了这个例外:

 *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MainViewController 0x431fac0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key searchDateLabel.'

在没有 Cocoa Bindings(仅在 Cocoa 中可用,而不是 Cocoa Touch)的情况下,我认为这两者没有关系。

在 Xcode 中,在 objc_exception_throw 上添加一个符号断点,然后在调试器中运行您的应用程序。当它中断时,查看调用堆栈。您将能够找到问题的真正根源。

【讨论】:

以上是关于如何创建一个具有多个 ViewController 可以使用的关联视图类的 Nib的主要内容,如果未能解决你的问题,请参考以下文章

具有多个行为模型的 ViewController

在多个 viewController 中显示的通用或单个 uipickerview

我试图在我的 ViewController 上放置多个 UICollectionView,但模拟中只有一个 UICollectionView 正在运行

在具有多个故事板的应用程序中以编程方式从 Storyboard 加载 ViewController

XCode 文本字段将无法连接到 ViewController

如何在一个ViewController中创建实现多协议?