故事板 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元素创建IBOutlets
和IBActions
。
【问题讨论】:
我尝试将视图拆分为它自己的笔尖,但我看到了同样的问题。 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的主要内容,如果未能解决你的问题,请参考以下文章