当用户切换到另一个程序然后再返回时,原始程序的视图将被另一个程序的新视图替换。那么当用户切换回原始程序时,第二次会调用viewDidLoad吗?
我问这个是因为如果是这种情况,那么每当用户来回切换屏幕时,就会执行viewDidLoad中的初始化代码。这可能会导致重置视图并丢失用户未完成的作品......
答案 0 :(得分:29)
不要在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
。只要它不在屏幕上,它就可以被卸载,通常是在内存不足时。
如果您确实在viewDidLoad
中设置了内容(例如,以编程方式添加子视图),则应始终在viewDidUnload
中再次取消设置。
将viewDidLoad
和viewDidUnload
视为视图控制器的view属性的init / dealloc。对于与视图相关的内容,请在这些方法中创建和释放它。对于与控制器本身相关的内容,请在initWithNibName
和dealloc
中创建并发布。
更新:在iOS 6及更高版本中,viewDidUnload
永远不再被调用(除非视图中的视图显式设置为nil),因此viewDidLoad
将通常只在视图控制器的生命周期中调用一次。这使得上面的建议不那么重要,但它仍然是最佳实践,如果你需要支持iOS 5及更早版本,它仍然是必需的。
更新2:如果您从故事板(现在是推荐的做法)加载视图控制器而不是以编程方式创建它,则不会调用initWithNibName:bundle:
。使用initWithCoder:
或awakeFromNib
来初始化您的控制器。
答案 1 :(得分:17)
@Nick Lockwood提供了极好的信息,但还有一些事情需要记住。
首先,如果从nib文件或故事板中实例化视图控制器,则不会调用initWithNibName:bundle:
。在这种情况下,会调用initWithCoder:
和awakeFromNib
。这种情况在iOS上有点不常见,但随着故事板的增加,视图控制器绕过initWithNibName:bundle:
更为常见。
我建议将非UI初始化代码放在一个单独的方法中(我称之为我的setup
)并从initWithNibName:bundle:
和awakeFromNib
调用它。但是我只会这样做,如果初始化只运行一次很重要。否则我将它放在viewWillAppear:
中以尽可能地延迟加载。
其次,您不应该在self.view
或init...
中执行引用awakeFromNib
的任何操作。在调用self.view
之前,您不应该引用viewDidLoad
(否则您将强制加载nib文件,而不是需要它)。如果与设置视图相关,则与{0}相关的内容应该在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
答案 2 :(得分:5)
-viewDidLoad
一次。显然,这将在控制器第一次访问其视图时发生。如果视图控制器稍后卸载其视图,则下次加载视图时将再次调用-viewDidLoad
。视图控制器不会因为视图被隐藏而卸载视图,但如果内存开始变低则可能会这样做。
视图控制器应该知道其视图的状态,并能够在-viewDidLoad
方法中根据需要进行设置。视图不应该用于存储状态 - 因为视图被卸载,所以不应该不可避免地丢失任何内容。
答案 3 :(得分:5)
因此,当用户切换回原始程序时,会 viewDidLoad第二次被调用?
(以上是来自op)
在这些情况下,有两种方法可供调用:
- (void)applicationWillEnterForeground:(UIApplication *)application;
重新打开后台应用程序(从任务管理器或再次从跳板开始)
解锁应用程序处于活动状态时锁定的设备。
- (void)applicationDidBecomeActive:(UIApplication *)application
打完电话后 通知中心解雇 任务经理被解雇(双击主页按钮并再次双击)
答案 4 :(得分:3)
来自the docs:
在视图控制器将其关联的视图加载到内存后调用此方法。
因此,只要视图控制器将其视图加载到内存中,就会调用它。这可能是第一次加载视图而且从不再次加载,或者每次视图在视图卸载时都可见(viewDidUnload
由于内存限制等)。