视图控制器生命周期
视图控制器有“生命周期”
随着它的进展,一系列的消息发送给它们
为什么要这样做?
常常通过重写这些方法来做某些工作
生命周期的开始…
创造
MVC在storyboard最常见的实例化(如你所见)
在代码中(罕见)很多方式可以做到这一点
然后呢?
设置输出口
出现和消失
几何变化
内存不足的情况
每个阶段,iOS在
控制器上调用方法(多次)...
在初始化和输出口设置之后,viewDidLoad被调用
这是一个非常好的地方去放入大量的设置代码
- (void)viewDidLoad
{
[super viewDidLoad]; //在生命周期方法中总是让super有一个机会
//做一些自己的MVC的设置
}
但要小心,因为你的视图(其边界)的几何形状还没有设置!
在这一点,你不能确定的你是在iPhone5的屏幕尺寸还是iPad还是???上
所以不要在这里做依靠几何的初始化
仅在视图出现在屏幕之前,你会得到通知
(参数就是,你是否会立即或在一段时间,通过动画显示)
- (void)viewWillAppear:(BOOL)animated;
你的视图将只“loaded”一次,但它可能会出现和消失了很多次
所以不要把真正想放在viewDidLoad中的东西在这个方法中
否则,你可会一遍又一遍的做不必要的事
你的MVC离开屏幕期间,如果你显示的事情要发生变化,在这里做
稍后我们将使用这个去优化性能,等到了这个方法时
(相对于viewDidLoad)开启代价高的操作(可能在另一个线程)
视图的几何形状在这里设置,但也有其他的(更好?)对几何做出反应
并且当你将要消失视图屏幕外也会得到通知
这是一个放入“记录发生了什么”和清理代码的地方
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated]; //在所有的viewWill/Did
方法中调用super...
//让我们更好的记住用户滚动的位置在哪...
[self rememberScrollPosition]; //当然我们将实现这个
//我们将从屏幕上被移除时,做一些其他的清理
[self saveDataToPermanentStore]; //也许没做?
//但要注意,不要在这里做一些费时的,否则应用将变慢
//甚至开启线程去做什么,需要在这里去做 (同样,我们将在后面讨论线程)
}
还有两个“did”版本的出现方法
- (void)viewDidAppear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
几何形状改变了吗?
多数情况,这将被与自动布局一起自动处理
- (void)view{Will,Did}LayoutSubviews;
任何时候视图的frame发生改变,它的子视图也随着重新布局
例如,自动旋转
你可以在这里重设你的子视图的frames或者设置其他几个性能的属性
在“will”与”did“之间,自动布局将会发生
自动旋转
当设备旋转时,顶级视图控制器将其边界重新调整,仅当…
视图控制器shouldAutorotate返回的是YES
试图控制器在supportedInterfaceOrientations返回新的定向
应用程序允许旋转的方法(在Info.plist文件中定义)
在MVC中支持旋转通常是个好的主意
具体通知,旋转将要/已经发生时
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)anOrientation
duration:(NSTimeInterval)seconds;
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOriention)orient
duration:(NSTimeInterval)seconds;
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)anOrientation;
当上面的上面的任意一个调用时,属性将有一个当前的方向
@property UIInterfaceOrientation interfaceOrientation;
实现这些非常罕见,自动布局和viewWillLayoutSubviews通常已经足够了
内存不足的情况,didReceiveMemoryWarning被调用...
这很少发生,但是内存开销大与精心设计的代码可能会预计它
比如:图片和声音
任何“大的”可以重现的或许应该被释放(即,设置strong指针为nil)
awakeFromNib
这个方法发送给所有从storyboard中出来的对象(包括你的视图控制器)
发生在输出口被设置之前!(即,MVC“loaded”之前)
把代码放在其他地方,如果可以(例如viewDidLoad中或viewWillAppear:)
你的控制器中的运行的任何的init方法,也必须在你的awekeFromNib运行
(因为storyboard出来的的对象不能调用init方法)
-(void)setup{ }; //做一些不能等到viewDidLoad的事
- (void)awakeFromNib { [self setup]; }
// UIViewController的指定初始化是initWithNibName:bundle: (呸!)
- (
id
)initWithNibName:(
NSString
*)nibNameOrNil bundle:(
NSBundle
*)nibBundleOrNil
{
self = [ super initWithNibName :nibNameOrNil bundle :nibBundleOrNil];
self = [ super initWithNibName :nibNameOrNil bundle :nibBundleOrNil];
[self setup];
return
self
;
}
}
这是不可能的,在这门课程,你永远都需要使用awakeFromNib
总结
实例化(从storyboard - 许多方式可以做到,以后会将)
awakeFromNib
输出口 get set
viewDidLoad
(在几何上确定时)
viewWillLayoutSubviews:与viewDidLayoutSubviews:
(接下来这组反复发生…) viewWillAppear:与viewDidAppear:
(每当几何上再次发生改变,如设备旋转) viewWillLayoutSubviews: 与viewDidLayoutSubviews:
(如果是自动旋转,那么你也会获得will/didRotateTo/From消息--很少使用这些) viewWillDisappear: and viewDidDisappear:
(内存不足问题...) didReceiveMemoryWarning
(没有任何关于“unload”的,因此所有的就这些了)
Demo
NSNotification
通知
MVC模式图(第一章中)的“radio station”
NSNotificationCenter
通过
[
NSNotificationCenter
defaultCenter
]获取默认的“通知中心”
然后,如果你想“收听电台”发送以下消息:
- (
void
)addObserver:(
id
)observer
//
你
(
得到通知的对象
)
selector:( SEL )aSelector // 调用方法,如果什么事情发生
name:(NSString *)aName // 电台名称 ( 常量,在一些地方 )
object:( id )anObject; // 改变你所感兴趣的 (nil 是所有的 )
selector:( SEL )aSelector // 调用方法,如果什么事情发生
name:(NSString *)aName // 电台名称 ( 常量,在一些地方 )
object:( id )anObject; // 改变你所感兴趣的 (nil 是所有的 )
当那里广播的时候,你将收到通知
- (void)methodToInvokeIfSomethingHappens:(NSNotification *)notification
{
notification.name //上面传递的名字
notification.object //发送给你通知的对象
notification.userInfo //通知具体发生了什么信息
}
完成收听一定要“关掉”
[center removeObserver:self];
或
[center removeObserver:self name:UIContentSizeCategoryDidChangeNotification object:nil];
如果不及时移除自身,有时会导致崩溃。
这是因为NSNotificationCenter保持一个“unsafe retained”指针指向你
一个移除自身的好地方是,当你的MVC的视图离开屏幕
或者你可以移除自身在一个叫做dealloc的方法中
- (void)dealloc
{
//注意这个方法!不能访问属性!你几乎从堆中消失!
[[NSNotificationCenter defaultCenter] removeObserver:self];
}