故事板 instantiateViewControllerWithIdentifier 未设置 IBOutlets

Posted

技术标签:

【中文标题】故事板 instantiateViewControllerWithIdentifier 未设置 IBOutlets【英文标题】:storyboard instantiateViewControllerWithIdentifier not setting IBOutlets 【发布时间】:2012-09-13 10:38:38 【问题描述】:

我正在使用故事板instantiateViewControllerWithIdentifier:,我注意到我连接的所有IBOutlets 仍然为零。但是,IBActions 我已经完成了工作。视图和控制器是链接的(即 controller.view 不是 nil),如果我显示视图,它会显示我所期望的。

我错过了什么?

这是我的设置:

    我的情节提要中定义了一个视图控制器。我给了它一个标识符,它与我在调用 instantiateViewControllerWithIdentifier: 时使用的标识符相同 我通过单击视图控制器(就在 First Responder 下方)设置了视图的所有者,并在 Identity Inspector 下将自定义类设置为与我想将视图连接到的类的名称相同。李> 然后我打开助手编辑器,控制拖动UI元素创建IBOutletsIBActions

【问题讨论】:

我尝试将视图拆分为它自己的笔尖,但我看到了同样的问题。 initWithNibName:bundle: 似乎也没有设置 IBOutlets,即使它们是通过 IB 中的 ctrl-click-drag 定义的。 作为一种解决方法,我正在使用 [[NSBundle mainBundle] loadNibNamed:@"myNib" owner:controller options:nil]。这确实会加载 nib 并将 IBOutlets 分配给控制器中的值。但是当控制器上有一个方法看起来在做同样的事情时,这似乎是错误的。 我对你的设置有点困惑,你为什么要设置视图的所有者?您的 ib 插座被放置在故事板上的视图控制器中,对吗?当您实例化此视图控制器时,如果您设置此 VC 的类型以匹配您的自定义标头和实现,则插座应该可以工作。 更正:我没有设置视图的所有者,而是视图控制器类类型匹配自定义类类型。 如果您控制点击情节提要中视图控制器的图标表示以显示连接 HUD,您是否看到所有插座都已连接? 【参考方案1】:

视图似乎只有在第一次访问后才被正确初始化。调用时问题消失

[self presentViewController:vc animated:NO completion:nil];

或者更简单

[vc view];

【讨论】:

这真的很奇怪。我的意思是,你知道这是否是正确的行为吗?这已经让我发疯了两天,直到我找到你的答案。 我不确定这是否正确,但这是可以理解的。为什么仅仅因为创建了视图控制器就设置了视图和所有内容。可以假设您在拥有视图控制器时想要该视图,但谁知道是什么优化导致了这种行为。不过,它应该记录在某个地方。 它有效,谢谢!我同意,它应该包含在文档中【参考方案2】:

[拿我当坏榜样]

毕竟这可能不是一个好主意,它可以工作,但它违反了常规加载,使应用程序不稳定^_^。 我会在此处留下答案,以防其他人想知道您是否这样做。


我遇到了同样的问题,但是我设计的自定义组件没有通过 presentViewController 加载(加载到上一个视图的覆盖中)

你可以直接调用

myViewController.loadView() //斯威夫特

[myViewController loadView] //Obj-C

【讨论】:

来自文档:You should never call this method directly.。首先我只是盲目地复制了这段代码并加载了我的视图,但后来我遇到了其他我无法解释的问题。删除此代码后,一切正常。我强烈建议不要调用此方法。 我建议不要遵循上述评论 错误答案:这将抑制 viewDidLoad() 的调用!如果你 - 无论如何 - 必须强制加载视图 - 使用 loadViewIfNeeded()。【参考方案3】:

Outlets 是通过键值编码建立的,你可以把它放到你的视图控制器子类中:

- (void)setValue:(id)value forKeyPath:(NSString *)keyPath 
    [super setValue:value forKeyPath:keyPath];


- (void)setValue:(id)value forKey:(NSString *)key 
    [super setValue:value forKeyPath:key];

并在对 super 的两次调用上设置断点。

在调试器中,我会尝试:

    将 'self' 与您认为要应用插座的视图控制器进行比较。也许您的故事板有您不期望的第二个视图控制器。当您说您“设置所有者”时,我认为这是一个奇怪的术语。除了已经存在的表示之外,您是否拖出了一个立方体对象来表示您的视图控制器?

    将 [self valueForKey:key] 或 [self valueForKeyPath:keyPath] 或仅 [self outletName] 与调用 super 后传入的值进行比较。也许您的二传手没有按照您的意愿行事。我已经看到这样的错误出现了几次,人们有一个名为“firstName”之类的对象的出口,然后是一个带有选择器“setFirstName:”的操作。这会混淆键值编码,最终会在 nib 加载期间调用 setFirstName: 以建立出口,但出口的设置器是作为操作方法实现的,因此永远不会设置出口。

【讨论】:

【参考方案4】:

为实例化的 ViewController 设置框架似乎设置了 IBOutlets。

例如:

DemoViewController *demoVC = [[self storyboard] instantiateViewControllerWithIdentifier:@"demoVC"];
demoVC.frame = self.view.frame; //or CGRectMake(0, 0, 1015, 604);

这将初始化 DemoViewController 的 IBOutlets,如 Label、TextField、Button、Table 等。

希望这会有所帮助。

【讨论】:

访问view 有什么魔力,而不是设置frame。它适用于视图层次结构内部的插座(不是自定义NSObject 的插座)。【参考方案5】:

如果您要链接的对象是场景中的***实体,例如 ArrayController,则引用必须是强的(而不是弱的!),因为视图层次结构不会保留它。弱引用可能会导致您描述的问题。

查看这里了解更多信息:Should IBOutlets be strong or weak under ARC?

【讨论】:

【参考方案6】:

人们给出了如何加载视图的解决方案(其中一些你永远不应该使用 (loadView()) 所以这里有一种方法来检查你的视图是否已经加载

我遇到了这个问题,因为我有一个带有 didSet 观察者的属性来更新 UI,如果尚未设置插座,这显然不起作用,所以这里有一些示例代码如何解决它:

var name: String? 
    didSet 
        updateNameLabel()
    


override func viewDidLoad() 
    super.viewDidLoad()

    updateNameLabel()


func updateRoomLabel() 
    guard isViewLoaded() else 
        return
    
    [...]

所以现在当您显示网点时会更新,但每次更新属性时也会更新

【讨论】:

以上是关于故事板 instantiateViewControllerWithIdentifier 未设置 IBOutlets的主要内容,如果未能解决你的问题,请参考以下文章

如何重命名故事板并保留来自其他故事板的链接

在多故事板应用程序中将支持的方向限制为特定故事板[关闭]

从一个故事板转到另一个故事板?

在从一个故事板解雇到另一个故事板时,它最近很快就被解雇了

故事板:如何使用故事板为 UIPageViewController 设置初始视图控制器?

将第二个故事板控制器分配给第一个故事板标签栏项目。