等待instantiateViewControllerWithIdentifier实例化完成

3

我有一个Storyboard,并且通过以下代码从代码中实例化一个视图控制器:

NSLog(@"1");
MyController *vc = (MyController *)[[UIStoryboard storyBoardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"MyController"];
NSLog(@"4");

MyController类的实现包括以下内容:
- (void)viewDidLoad {
    NSLog(@"2");
    [super viewDidLoad];
    [NSThread sleepForTimeInterval:2];
    NSLog(@"3");
}

当我运行我的代码时,我希望看到以下输出结果:
1
2
3
4

但似乎只有在访问MyController的视图后才会调用-viewDidLoad

1
4

如果我将第一个修改为这样:
NSLog(@"1");
MyController *vc = (MyController *)[[UIStoryboard storyBoardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"MyController"];
[vc view]; // Just accessing
NSLog(@"4");

然后输出将会是:
1
4
2
3

如何确保我的属性已初始化(-viewDidLoad 已运行),并且我可以给控制器传递参数?推荐的方法是什么?


你不使用segue的原因是什么?我几乎总是使用它来从storyboard中呈现VC。 - Tim
这个特定的控制器是从地图标注视图中打开的。你不能使用直接转换(比如从按钮到控制器),只能间接转换(从一个控制器到另一个控制器)。而后者也存在同样的问题(请参考这里:http://stackoverflow.com/questions/32639850/pass-variable-to-view-controller-before-viewdidload)。 - gklka
我猜我还是不明白你在新VC中设置的内容,为什么不能通过segue设置。我会通过prepareForSegue设置变量,然后在viewWillAppear中进行不同视觉效果(按钮隐藏/显示)的设置,而不是在viewDidLoad中设置。 - Tim
1
如果您创建了一个类变量,例如var fromAddress : String?并通过prepareForSegue传递它,为什么它不能工作?然后在viewWillAppear中,将textfield.text设置为fromAddress - Tim
@Tim 这会起作用。我只是想避免引入这些不必要的属性。 - gklka
显示剩余3条评论
2个回答

1
这是因为viewDidLoad只有在以模态方式呈现视图控制器、将其推入导航控制器或以某种方式显示它后才会调用。因此,如果您想要接收1、2、3、4,则需要像这样做:
NSLog(@"1");
MyController *vc = (MyController *)[[UIStoryboard storyBoardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"MyController"];
[self presentViewController:vc animated:YES completion:^{
    NSLog(@"4");
}];

如果我想将控制器推入到 UINavigationController 中怎么办? - gklka

1
你应该编写VC,使其不依赖于视图在属性设置前或后是否已加载。
如果你有这样的一个属性:
@property (nonatomic, copy) NSString *superAwesomeLabelText;

您需要设置超级棒标签的文本,具体步骤如下:

viewDidLoad中实现:

self.superAwesomeLabel.text = (self.superAwesomeLabelText) ?: @"Default lame text";

superAwesomeLabelText的设置器:

- (void)setSuperAwesomeLabelText:(NSString*)superAwesomeLabelText {
    _superAwesomeLabelText = [superAwesomeLabelText copy];

   self.superAwesomeLabel.text = superAwesomeLabelText;
}

现在视图在属性设置前或后加载都没有关系。

1
相关要点:我在很久以前学习面向对象编程时学到的最重要的一课是避免属性依赖。一个对象应该可以在不设置任何属性的情况下使用,并且属性设置和/或方法调用的顺序永远不应该有影响。现在,这是一个理想状态,在实际编程中我们经常无法做到这一点。但永远不要失去这个理想! - Avi
但是如果您正在为两个几乎相同的目的使用控制器,并且没有init方法可用,那么您如何实现这一点呢? - gklka
你怎么可能没有一个初始化方法来使用?而且要实现什么,确切地说? - Avi
如果我在Storyboard中定义了我的UI,那么我只能使用-instantiateViewControllerWithIdentifier:来实例化它。这个方法会给我一个初始化的实例,我不能重新初始化它。 - gklka
  1. 你可以使用 initWithNibNamed:... 或者 initWithCoder:...,其中一个会在从故事板实例化时调用(我不记得是哪个了)。
  2. 原帖提到了 viewDidLoad,这很有道理,因为那是你知道你有一个视图可以自定义的最早时间点。
- Avi
你能帮我用你提到的方法从Storyboard(而不是单独的xib文件)实例化一个视图控制器吗? - gklka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接