【问题标题】:Using Interface Builder efficiently有效地使用界面生成器
【发布时间】:2025-12-01 04:10:02
【问题描述】:

我是 iPhone 和目标 c 的新手。我花了几个小时和几个小时阅读文档并试图了解事情是如何运作的。我有 RTFM 或至少正在处理中。

我的主要问题是我想了解如何指定事件传递到的位置,并且我能够做到这一点的唯一方法是指定委托,但我确信在 IB 中有一种更简单/更快的方法。

所以,举个例子。 假设我有 20 个不同的视图和视图控制器以及一个 MyAppDelegate。 我希望能够在 IB 中构建所有这些不同的 Xib 文件并添加许多按钮和文本字段等等,然后指定它们都在 MyAppDelegate 对象中产生一些事件。为此,我在 IB 列表视图的每个视图控制器中添加了一个 MyAppDelegate 对象。然后我在 XCode 中的 MyAppDelegate 中创建了一个 IBAction 方法并返回到 IB 并将所有事件链接到每个 Xib 文件中的 MyAppDelegate 对象。

但是,当我尝试运行它时,它却因错误的读取异常而崩溃。

我的猜测是每个 Xib 文件都放置了一个 MyAppDelegate 对象指针,该指针与最终将在运行时实际创建的 MyAppDelegate 地址无关。

所以我的问题是……我该怎么做?!!!

【问题讨论】:

    标签: iphone xcode delegates interface-builder ibaction


    【解决方案1】:

    如果您在每个 nib 文件中创建 MyAppDelegate 的实例,那么,是的,当所有 nib 加载时,您最终会得到该类的许多不同实例。应用程序委托不是由类甚至协议标识的,而是由应用程序实例的delegate 属性指向的对象。要找到真正的应用程序委托,您必须向应用程序对象本身询问其委托

    您应该让所有视图控制器都从具有appDelegate 属性的父视图控制器类继承。实现这样的东西:

    #import "MyAppDelegateClass.h"
    
    @interface ViewControllerBaseClass :UIViewController {
        MyAppDelegateClass *appDelegate;
    }
    @property(nonatomic, retain)  *appDelegate;
    
    @end
    
    @implementation ViewControllerBaseClass
    @synthesize appDelegate;
    
    -(MyAppDelegateClass *) appDelegate{
        self.appDelegate=(MyAppDelegateClass *)[[UIApplication sharedInstance] delegate];
        return appDelegate;
    }
    @end
    

    当视图控制器需要应用委托时,它只需调用self.appDelegate。如果您想访问应用程序委托的属性,请使用self.appDelegate.attributeName

    重要的是您在运行时向应用程序询问其特定的委托实例。你不能从 nib 文件中做到这一点。

    【讨论】:

    • 如果我说@property (nonatomic,retain) IBOutlet MyAppDelegateClass *appDelegate 然后从这个基础 Viewcontroller 子类化我的每个视图控制器,然后在我的 AppDelegate 本身中添加各种 IBAction 方法,那么肯定有一些在Interface builder中而不是在代码中连接那些IBOutlets的方法?到目前为止,我已经通过在从 MyAppDelegateClass 中加载视图控制器时将 appDelegate 属性设置为 self 以编程方式完成了它,但我认为 [UIApplication ...] 行会更好。但是IB里面没有办法吗??
    • 应用委托是一个特定的实例。您必须指向该特定实例,否则您无法联系到实际的代表。简单地给一个类一个出口不会让它的子类指向一个特定的实例。这些出口中的每一个都必须链接到应用程序对象用作其委托的特定应用程序委托实例。
    • Nib 文件旨在模块化并具有有限的范围。按照设计,它们不依赖也看不到整个应用程序甚至应用程序对象。因此,只有应用程序对象本身(通常是 MainWindo.nib)拥有的 nib 才能看到活动委托。
    • 如果想在 IB 中连接它,您可以创建一个小型实用程序类,其功能是查找活动的应用程序委托实例。然后,您可以将该类添加到任何随机笔尖并将插座连接到该笔尖。这将使您无需子类化就可以在 nibs 中管理对应用程序委托的访问。
    • 好的,很好的答案。非常感谢您的时间和高效的响应。
    【解决方案2】:

    我不完全清楚你到底想做什么,但这可能是个坏主意。每个应用程序应该只有一个应用程序委托,它应该处理整个应用程序的行为。通常,应用程序委托初始化根视图控制器并显示它们,但仅此而已(除了处理诸如打开和保存数据源之类的事情)。

    视图控制器(UIViewController 的子类)应该与 XIB 交互。在视图控制器中具有特定于视图的行为使应用程序更易于管理和维护。通常,每个视图控制器应该有 0 或 1 个 XIB(比这更复杂)。您使用带有 IBOutlets 和 IBActions 的 Target/Action 模式设置与视图的交互(请参阅here 以获取完整指南)。使视图控制器或 XIB 依赖于应用程序委托通常是一个坏主意(因为再次减少依赖关系会使代码更易于管理)。

    【讨论】:

    • 好的,那我会问一个稍微不同的问题。如何创建一个视图控制器来控制多个不同的视图,其中每个视图都在单独的 nib 文件中定义。假设我在 5 个不同的笔尖中构建了 5 个视图,除了视图之外,笔尖层次结构中没有其他任何内容。现在我用视图控制器构建了一个笔尖,但没有视图。如何使用运行时指定的视图初始化 MyAppViewController。 UIView 中有一个选项可以做到这一点吗?然后我是否必须将每个 nib-with-only-a-view 的文件所有者设置为 MyAppViewController 类型?或者应该怎么做?
    【解决方案3】:

    一般来说,您应该为正在构建的每个视图创建一个视图控制器,并将事件链接到这些视图控制器 - 而不是应用程序委托。事实上,通常不会有任何事件从任何 nib 文件连接到应用程序委托,即使在示例项目中,您也会注意到视图控制器是由应用程序委托创建并保留的,但它不接收事件。

    【讨论】: