我应该在ViewDidAppear、ViewDidLoad、ViewWillAppear或构造函数中以编程方式添加子视图吗?

25

我正试图从苹果的含糊不清的文档中找出初始化并将我的视图控件添加到控制器视图的最佳方法。

使用WinForms相对简单,因为它们始终在构造函数中调用的InitializeDesigner中初始化。如果可能,我正在尝试匹配此模式的可靠性。

我大多数时间都使用UINavigationController中的UIViewControllersUITableViewControllers——如果这会影响它的话。

以下是一个示例:

public MyController()
{
    // Here?
    AddViews();
}

public override ViewDidLoad()
{
    base.ViewDidLoad();

    // Or is should it be here?
    AddViews();
}

public override ViewWillAppear(bool )
{
    base.ViewWillAppear(animated);

    // Here?
    AddViews();
}

public override ViewDidAppear(bool animated)
{
    base.ViewDidLoad(animated);

    // Or maybe here?
    AddViews();
}

void AddViews()
{
    UILabel label = new UILabel();
    label.Text = "Test";
    label.Frame = new RectangleF(100,100,100,26);
    View.AddSubView(label);

    UIWebView webview = new UIWebView();
    webview .Frame = new RectangleF(100,100,100,26);
    View.AddSubView(webview);
}

当我将一些UI控件添加到视图的不同位置时,有时会出现视觉延迟,而有时Webview则被隐藏在某个地方。是否有一般规则可遵循以进行添加?


2
参见:https://dev59.com/3XRB5IYBdhLWcg3wn4QL什么是loadview和viewdidload之间的区别 - Chris S
3个回答

73

一般来说,我的做法如下:

  • ViewDidLoad - 每当我要将控件添加到应该与视图一起显示的视图中时,我会立即将其放入 ViewDidLoad 方法中。基本上,每当将视图加载到内存中时,就会调用此方法。例如,如果我的视图是一个包含3个标签的表单,则会在此处添加标签;没有这些表单,该视图将永远不存在。

  • ViewWillAppear:我通常使用 ViewWillAppear 来更新表单上的数据。因此,对于上面的示例,我将使用它来实际从我的域中加载数据到表单中。创建 UIViews 非常昂贵,您应该尽可能避免在 ViewWillAppear 方法中执行此操作,因为当调用它时,意味着 iPhone 已经准备好向用户显示 UIView,并且您在此处执行的任何繁重操作都会以非常明显的方式影响性能(如动画延迟等)。

  • ViewDidAppear:最后,我使用 ViewDidAppear 来启动新线程执行需要很长时间才能执行的任务,例如执行 Web 服务调用以获取上述表单的额外数据。好处是,因为视图已经存在并正在显示给用户,所以您可以向用户显示一个漂亮的“等待”消息,同时获取数据。

当然,还有其他技巧可以使用。比如说,您希望在表单加载后让 UILabel “飞”进表单中。在这种情况下,我会将标签添加到 ViewDidLoad 中,但 Frame 位于视图区域之外,然后在 ViewDidAppear 中执行动画将其飞回视图中。

希望对您有所帮助。


谢谢,这解决了很多问题。我无法使用此问题中的LoadView示例添加任何内容:https://dev59.com/3XRB5IYBdhLWcg3wn4QL - 你是否曾经使用过这种方法? - Chris S
2
所以基本上loadView是UIViewController的一个方法(当你试图弄清这些东西时,请使用罗塞塔石头 - http://tirania.org/tmp/rosetta.html)。框架会自动调用此方法来告诉控制器创建视图,并且UIViewController的默认实现随后调用ViewDidLoad。虽然您可以重写此方法(并确保在执行此操作时调用基础方法),但我个人更喜欢仅使用viewWillLoad(在loadView之前调用)和viewDidLoad(在其后立即调用)。 - Eduardo Scoz
我不同意你不应该调用它;这取决于你想要的行为。如果你继承了一个ViewController并想使用父类创建的视图,那么是的,你需要显式地调用super.loadView。这取决于情况,但你不想发生的事情是让你的超类创建视图,然后在你的重载中将其丢弃。 - Eduardo Scoz

9
嗯,苹果的文档看起来非常清晰。如果您以编程方式创建自己的根视图(此特定控制器视图层次结构的根视图),则应在-loadView中创建它而不调用super,并在完成后设置view属性。如果您的视图是从nib加载的,则不应触摸-loadView。
您可以在-viewDidLoad中向视图控制器的视图添加自定义子视图或以其他方式修改它。建议的做法是在-viewDidLoad中创建您的UILabel和UIWebView,并在-viewDidUnload中释放它们,如果需要将其保留在ivars中,则将其引用设置为nil。
注意:在iOS 6中,-viewDidUnload已被弃用并且不再被调用,因为UIViewController在内存压力下不再清除其视图。

谢谢,我错过了那个方法。然而,我仍然觉得我列出的方法提供的信息非常有限,无法告诉我们何时使用它们。即使在loadView中,你只被告知“如果你想对你的视图进行任何其他初始化,请在viewDidLoad方法中执行” - 你何时需要这个方法呢? - Chris S
loadView是一种方法,它可以从NIB中加载视图层次结构,或者如果没有NIB可用,则创建一个空的UIView。如果您想要自定义视图,那么您可以重写loadView方法。例如,UITableViewController会覆盖此方法以创建UITableView。我经常发现自己在我的自定义UIView子类中做同样的事情。 - Costique
viewDidUnload已被弃用 - Display Name
@SargeBorsch 是的,答案太老了。谢谢,我更新了这一部分。 - Costique

2
viewDidLoad涉及到“内存”,而viewWillAppear/viewDidAppear涉及到“外观”。一个视图控制器的视图(即视图控制器视图的根视图)可以出现/消失多次,即使控制器的视图已经在内存中。
(当涉及根视图时,我也指它的子视图,因为根视图有参考其子视图的引用,但从视图控制器的角度来看,它通常只知道根视图。对子视图的引用通常通过视图控制器的输出口进行。)
根视图本身可能会在出现内存警告时从内存中移除。视图控制器将确定何时最好将它们从内存中移除。
因此,您通常会在viewDidLoad中添加子视图,因为添加子视图意味着将它们添加到内存中。但是,如果您完全以编程方式创建所有视图(而不是从nib文件中创建),则应覆盖loadView方法,并在那里创建根视图并添加子视图,在这种情况下,您可以省略viewDidLoad以添加子视图。

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