iOS5如何“懒惰地”初始化标签栏的控制器?

Posted

技术标签:

【中文标题】iOS5如何“懒惰地”初始化标签栏的控制器?【英文标题】:iOS5 how to "lazily" initialize controllers for the tab bar? 【发布时间】:2011-11-06 17:17:14 【问题描述】:

我有一个最多有 9 个控制器的 TabBar 控制器,每个控制器都有一个导航控制器。目前,我在

的应用程序委托中分配和初始化它们中的每一个
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions...

这使我的应用在首次启动时需要相当长的时间才能启动。我想通过延迟初始化来减少初始加载时间。

有没有办法在第一次选择标签栏时“懒惰地”初始化视图控制器

研究 ios5 的情节提要能帮我解决这个问题吗?

谢谢!

【问题讨论】:

分配初始化视图控制器应该不会花那么长时间。您可能需要优化它们并确保这些 ViewControllers 延迟加载它们的资源...提示:viewDidAppear 【参考方案1】:

将你的控制器定义为惰性控制器怎么样?

我的意思是,如果由于九个视图控制器的初始化,应用程序需要一些时间才能启动,那么这与控制器在初始化时实际执行的操作有关。因此,您可以分两步使控制器懒惰地初始化:一,当您将所有控制器添加到标签栏控制器时;二、当你选择一个特定的选项卡时,相应的控制器就会被初始化。

我认为这是最干净的方法。

否则,我会打赌直接使用UITabBar 在您自己的标签栏控制器类中管理它。

作为最后一个选项,我会尝试根据某些逻辑在适当的时间调用setViewControllers:animated: 来动态更改标签栏控制器的内容。例如,您可以在application:didFinishLaunchingWithOptions: 中仅使用 5 个视图控制器初始化标签栏控制器,然后稍后添加其余的...

但我的实际建议是让组件控制器变得懒惰......

编辑:在评论中阅读您的问题后...

如果你想尝试延迟初始化你的控制器,我的意思是:

    您将通过调用 [[... alloc] init...] 来初始化您的控制器(或 UIKit 在加载 nib 时);这没有改变;

    init 方法会将控制器初始化为其默认状态,例如设置属性和 ivar 值,并且不会执行更复杂的操作;

    在显示控制器视图之前,通过调用特定方法完成其初始化;这将完成“相当多的委托”部分,我认为这是初始化的冗长部分。

很抱歉,如果谈论“延迟初始化”导致组件的逻辑初始化与init方法的内容之间产生歧义。

至于第 3 点,您可以选择在哪里完成初始化。

可能是控制器即将显示时。在这种情况下,要么在标签栏控制器委托中定义-tabBarController:didSelectViewController:,要么使用viewWillAppear。这将为您提供最懒惰的初始化,但它可能会在您在视图出现之前选择选项卡的确切时刻添加一些延迟。

更好的是使用viewDidLoad,它会给你一种不那么懒惰的初始化; all 您的控制器的初始化将在您无法控制的某个时间点发生(当然,在视图显示之前),因此它可能会延迟一些事情,但不会发生在applicationDidFinishLoading 并且会更加 UI 友好,因为它将由主循环控制。绝对是第一个尝试的选择。也可以看看UIViewController reference中对viewDidLoad的描述。

最后是关于单独线程的注释。请记住,在单独的线程中使用 UIKit 并不完全安全,所以要小心。

【讨论】:

动态设置视图控制器的好主意!我注意到,由于我的控制器溢出到“更多”选项卡上,用户可以选择编辑控制器的顺序。我不知道此订单重新排列是否会在应用重新启动后持续存在。如果是这样,这是一个很酷的功能,我不想失去。 我所有的视图控制器都是从 Nibs 创建的,并且有很多委托正在进行。如果我错了,请纠正我,仅分配的对象只是一堆内存,所以我还不能分配它的属性。我想到的一件事是在 didFinishLaunchingWithOptions 中创建一个后台任务,并让它处理所有长时间运行的操作,例如预分配一些内存。 关于重排:我认为订单重排不会持续;您将不得不坚持下去...另请参阅我对您的其他评论的进一步编辑...【参考方案2】:

感觉就像在这个问题上添加一个快速的 .02。正如其他人指出的那样,UIViewController 初始化和加载过程已经“懒惰”了。真正的问题是您在初始化过程中做了什么,需要这么长时间?即使加载视图也不应该花费很长时间,因为您不希望用户在视图更改之前点击选项卡时等待。我建议如下:

    在 init 中,尽可能少做。 init 的目的是让任何独立于视图的数据初始化并准备就绪。您不应在此处加载任何视图。

    loadViewviewDidLoad 中创建所有视图/子视图。

    仅在需要时加载数据。如果您在 init 中需要它,请将其加载到那里。如果您可以等到视图加载完毕,请在viewDidLoad 中执行此操作。如果加载数据需要很长时间,请在后台加载。

【讨论】:

【参考方案3】:

在 UIViewController 的实现中,在方法中创建所有视图

- (void)viewDidLoad

并避免在您的 init 方法中创建视图(或更糟糕的是获取数据)。

默认情况下,UITabBarController 或 UINavigationController 将调用 viewDidLoad,即在用户看到它之前。

【讨论】:

我认为以编程方式创建视图的合适位置是-[UIViewController loadView],而不是-[UIViewController viewDidLoad] 在 Xcode 4.x 中,当我创建一个新的 UIViewController 子类时,我得到的只是 init 和 viewDidLoad。我可以确认 viewDidLoad 被懒惰地调用了。

以上是关于iOS5如何“懒惰地”初始化标签栏的控制器?的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate 无法懒惰地初始化角色集合 无法初始化代理 - 没有会话

懒惰地初始化角色集合失败

无法懒惰地初始化角色集合,..无法初始化代理 - 无会话 - JPA + SPRING

关闭模态视图并调用初始视图控制器

在将对象转换为json期间,无法懒惰地初始化角色集合

Spring Boot 中的 Hibernate 无法懒惰地初始化角色集合,无法初始化代理 - 没有 Session 异常