2012-02-04 144 views
18

当用户切换到另一个程序后又返回时,原始程序的视图将被另一个程序的新视图替换。所以当用户切换回原来的程序时,viewDidLoad会被第二次调用吗?viewDidLoad多久调用一次?

我问这个,因为如果是这种情况,那么放置在viewDidLoad中的初始化代码将在用户每次来回切换屏幕时执行。而这可能会导致正在重置的意见和失去用户的未完成的作品...

+0

感谢您的评论。 – Stanley 2012-02-04 01:31:15

+4

评论是不正确的。每次你的视图控制器的视图被加载时,它都会被调用,而不仅仅是第一次。 – 2012-02-04 01:35:43

+0

感谢您的更正... – Stanley 2012-02-04 01:48:51

回答

26

不要在viewDidLoad做视图控制器初始化。这是一个常见的错误。

对于东西是加载视图控制器时,应该只发生一次,做到在控制器的init方法,像这样:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil 
{ 
    if ((self = [super initWithNibName:nibNameOrNil bundle:bundleOrNil])) 
    { 
     //do your initialisation here 
    } 
    return self; 
} 

initWithNibName:bundle:方法被称为之前的画面从加载笔尖,并且在视图控制器的使用寿命中仅调用一次。

控制器的视图可以在控制器的使用寿命期间多次加载和卸载,并且每次都会调用。只要不在屏幕上,它可能会被卸载,通常如果内存不足的话。

如果你设置了viewDidLoad(例如,以编程方式添加子视图)的东西,你应该总是在viewDidUnload中再次取消它们。

viewDidLoadviewDidUnload想象为像视图控制器的视图属性的init/dealloc。对于与视图相关的内容,请在这些方法中创建并释放它。对于与控制器本身相关的内容,请在initWithNibNamedealloc中创建并释放它。

UPDATE:在iOS 6和后,viewDidUnload不会被调用任何更多(除非视图被明确设置为nil中的代码),等等viewDidLoad通常只进行一次在一个视图控制器的寿命称为。这使得建议不太重要,但这仍然是最佳实践,如果您需要支持iOS 5及更早版本,仍然是必要的。

更新2:如果您加载从故事板视图控制器(也就是现在推荐的做法),而不是编程方式创建它,然后initWithNibName:bundle:不会被调用。改为使用initWithCoder:awakeFromNib来初始化您的控制器。

+0

感谢您的详细解答... – Stanley 2012-02-04 01:29:52

+0

您说:“这种方法是在视图从笔尖加载之前调用”,什么是“this”是指“initWithNibName”还是“viewDidLoad”? – Stanley 2012-02-04 01:39:14

+0

道歉,我澄清了它。 – 2012-02-04 01:45:12

3

the docs:视图控制器加载其相关的意见到内存后

该方法被调用。

所以,只要视图控制器将其视图加载到内存中,就会调用它。这可能是第一次的看法是加载永不再,或每看法变得可见时,如果你的观点不断地卸载(viewDidUnload由于内存限制等)

+0

感谢您的回答... - – Stanley 2012-02-04 01:26:47

4

-viewDidLoad将被调用一次,每当视图控制器需要加载其视图层次结构。显然,这将在控制器首次访问其视图时发生。如果视图控制器稍后卸载其视图,则在下次加载视图时将再次调用-viewDidLoad。视图控制器不会因为隐藏视图而卸载其视图,但如果内存开始变慢,它可能会这样做。

视图控制器应该知道其视图的状态,并且可以根据需要在其-viewDidLoad方法中设置它们。不应该使用视图来存储状态 - 不应该因为视图被卸载而不可挽回地丢失。

+1

感谢您的详细解答... – Stanley 2012-02-04 01:26:11

+0

关于“视图控制器应该知道其视图的状态”,希望问这种“保持状态的能力”是我们的风俗责任代码还是内置在Cocoa库中? – Stanley 2012-02-04 01:46:13

+1

它不是内置的。关键是你的视图控制器不应该依靠视图来保持状态。例如,如果您的视图中有一个滑块,则视图控制器应该在其更改时记住该滑块的值。这样,如果视图被卸载然后再次加载,视图控制器可以将滑块重置为-viewDidLoad中保存的值。 – Caleb 2012-02-04 02:28:48

5

那么当用户切换回原来的程序时,会第二次调用 viewDidLoad?

(以上是从OP)

在这种情况下,有两种方法被称为:

- (void)applicationWillEnterForeground:(UIApplication *)application; 

重新打开转到后台运行的应用程序(从任务管理器或跳板再次)
解锁设备,该应用程序处于活动状态时被锁定。

- (void)applicationDidBecomeActive:(UIApplication *)application 

后打电话
通知中心解雇
任务管理器撤职(双击Home键&双再次点击)

+0

感谢您的详细解答... – Stanley 2012-02-04 01:30:20

17

@Nick洛克伍德提供优秀的信息,但也有一些事情要记住。

首先,如果视图控制器是从nib文件或故事板实例化的,则不会调用initWithNibName:bundle:。在这种情况下,调用initWithCoder:awakeFromNib。这种情况在iOS上有点不常见,但随着故事板的增加,现在视图控制器绕过initWithNibName:bundle:更为常见。

我建议把非UI初始化代码在一个单独的方法(我称之为我的setup)和来自initWithNibName:bundle:awakeFromNib调用它。但是,只有在初始化只运行一次非常重要的时候,我才会这样做。否则,我把它放在viewWillAppear:尽可能延迟加载。其次,你不应该做任何在init...awakeFromNib中引用self.view的东西。你永远不应该参考self.view,直到调用viewDidLoad(否则你会强制nib文件比需要的更早加载)。与UI有关的事情应该在viewDidLoad(如果它们与设置视图有关)或viewWillAppear:(如果它们与配置视图(即,用数据加载它们)有关)。

所以我的方式通常设置这些东西了:

@implementation 

- (void)setup { 
    // Non-UI initialization goes here. It will only ever be called once. 
} 

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle { 
    if ((self = [super initWithNibName:nibName bundle:bundle])) { 
    [self setup]; 
    } 

    return self; 
} 

- (void)awakeFromNib { 
    [self setup]; 
} 

- (void)viewDidLoad { 
    // Any UI-related configuration goes here. It may be called multiple times, 
    // but each time it is called, `self.view` will be freshly loaded from the nib 
    // file. 
} 

- (void)viewDidUnload { 
    [super viewDidUnload]; 
    // Set all IBOutlets to `nil` here. 
    // Drop any lazy-load data that you didn't drop in viewWillDisappear: 
} 

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    // Most data loading should go here to make sure the view matches the model 
    // every time it's put on the screen. This is also a good place to observe 
    // notifications and KVO, and to setup timers. 
} 

- (void)viewWillDisappear:(BOOL)animated { 
    [super viewWillDisappear:animated]; 
    // Unregister from notifications and KVO here (balancing viewWillAppear:). 
    // Stop timers. 
    // This is a good place to tidy things up, free memory, save things to 
    // the model, etc. 
} 

- (void)dealloc { 
    // standard release stuff if non-ARC 
    [[NSNotificationCenter defaultCenter] removeObvserver:self]; // If you observed anything 
    // Stop timers. 
    // Don't unregister KVO here. Observe and remove KVO in viewWill(Dis)appear. 
} 

@end 
+0

感谢您的详细解答... – Stanley 2012-02-04 02:08:25

+1

您应该真的添加一个viewDidUnload样本到您的很好的例子。 – Till 2012-02-05 14:38:15

+0

@谢谢你的提示。我忘记了包含viewDidUnload。固定。 – 2012-02-05 15:29:04