9、iOS应用界面切换(笔记知识源:Geekband & 网易云课堂,同时包括各类网上资源的查找)

iOS应用界面切换

  • 1、UIViewController 的生命周期;
  • 2、push & pop;
  • 3、presentModalView. (它是和 navigationController 无关的,是在所在的 viewController 添加一个模态 view)

iOS三种则视图切换的原理各不相同 (from:Kenshin Cui's Blog)

  • UITabBarController: 以平行的方式管理视图,各个视图之间往往关系不大,每个加入到UITabBarController的视图都会进行初始化,即使当前不显示在界面上这两句现在还不是很懂,相对比较占用内存优化的一个入口吗?。[tabBarItem 的 image 属性必须是png格式(建议32*32)并且打开alpha通道,否则无法正常显示]
  • UINavigationController: 以栈的方式管理视图,各个视图的切换就是压栈和出栈操作,出栈后的视图会立即销毁释放比较合适。[只有在栈顶的控制器能够显示在界面中。UINavigationController默认也不会显示任何视图,它必须有一个根控制器rootViewController,而且这个根控制器不会像其他子控制器一样会被销毁。]
  • UIModalController: 以模态窗口的形式管理视图,当前视图关闭前,无法在其它的视图上进行操作。
    对其blog进行研读并在以后做好笔记工作

(接下来先了解2和3的内容)
下面的代码了解push & pop 和 presentModalView 的方法。
在实现文件 .m 的 viewDidLoad 方法中输入以下代码:

"1号“代码段

UIBotton  *pushButton = [UIButton buttonWithType: UIButtonTypeCustom];
pushButton.frame = CGRectMake(10, 74, self.view.bounds.width - 20, 44);
[pushButton setBackgroundColor: [UIColor cyanColor]];
[pushButton setTittle: @"push a view" forState: UIControlStateNormal];
[pushButton setTitleColor: [UIColor blackColor] forState: UIControlStateNormal];
[pushButton addTarget: self
               action: @selector(pushButtonClicked)
     forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: pushButton];                          

接下来创建一个 presentButton,目的是为了演示 两种不同的页面切换方式:

“2号”代码段

UIBotton  *presentButton = [UIButton buttonWithType: UIButtonTypeCustom];
presentButton.frame = CGRectMake(10, 130, self.view.bounds.width - 20, 44);
[presentButton setBackgroundColor: [UIColor yellowColor]];
[presentButton setTittle: @"present a modal view" forState: UIControlStateNormal];
[presentButton setTitleColor: [UIColor blackColor] forState: UIControlStateNormal];
[presentButton addTarget: self
               action: @selector(presentButtonClicked)
     forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: presentButton];                          

上面有两段 选择器 selector 的代码。通过它们使界面进行跳转,不过首先要选定跳转到哪一个页面,在选定之后,在实现文件 .m 开头导入跳转后界面的控制器才会在执行方法后可以显示界面:

“3号”代码段

#import  "BLSubViewController.h"

接下来,先介绍下 push 操作:它类似于 UINavigationController 的压栈(先进后出)。下面演示上面两个 Button 所关联的 selector 跳转方法,第一个介绍的是 push (注意它们要跳转到的那个页面已经选定,就是刚导入的 BLSubViewController):

“4号”代码段

#pragma mark - Custom event methods

- (void)pushButtonClicked:(id)sender
{
    BLSubViewController *subViewController = [[BLSubViewController] init];
    [self.navigationController pushViewController:subViewController animated:YES];
}

也许在 animated: 中使用 YES 显得更贴近自然语言吧。
  上面方法中的两行代码就已经通过 push 将页面进行了跳转。 [首先创建了一个跳转目的界面的视图控制器,然后由当前界面视图控制器 push 到 目的地视图控制器
  上面的一个代码段介绍了 push 的方法,在跳转到 BLSubViewController 的界面之后,我们如果这时需要跳回到刚才那个页面,其时就是将刚刚押入的栈弹出(所谓的pop方法)。[其实,苹果已经帮我们在BLSubViewController 的界面设置了跳转回去的按钮,如下图:

左上角的 One 就是返回的控件

现在,我们需要自己来做一个 pop 回去,这样才算知道所以然.
  首先第一步和前面设置两个 button 控件一样的,先在 BLSubViewController 的界面 复制一样的代码,改掉相关的代码,selector 方法名 设置为:backButtonClicked:

“5号”代码段

- (void)backButtonClicked:(id)sender
{
    [self.navigationController popViewControllerAnimated:YES];
}

只方法中的一行代码就将其移除了。
  值得注意的是在 navigationController 中还为我们提供了另一个可以返回指定 UIViewController 的方法(所以它本身也是一个数组对象 NSArray):
**NSArray popToViewController:(UIViewController ) animated:(BOOL)
还有一个是返回 rootViewController:
NSArray popToRootViewControllerAnimated:(BOOL)
一般是上面代码段中的方法更加普遍使用,我个人认为比较中庸,但也实在。后面两个方法则是比较有针对性。


上面我们将文章一开头的 界面切换 中的第二点 push & pop 讲完了,现在来讲讲第三点 presentModalView。modalView是一个模态窗口(模态的你只能在该窗口进行操作,否则就是非模态窗口),它是盖在其它视图之上的。现在我们来完成 2号代码段 中的 selector :

- (void)presentButtonClicked:(id)sender
{
    BLSubViewController *subViewController = [[BLSubViewController alloc] init];
    [self presentViewController:subViewController animated:YES completion:nil];

    // 第二行代码中 self presentViewController:  由这个方法可以感知到,presentModalView 确实就是覆盖其上的一个视图控制器。
}

设置好之后,跳转后画面如下,presentModalView 即图中右边视图。注意 presentViewController:subViewController animated:YES completion:nil 是苹果的一个新方法,它代替了旧方法,当我们使用新方法的时候需要注意它是支持哪个版本的,根据自己项目的受众群体进行合理的设置,以免造成使用旧版系统的用户的应用崩溃。

presentModalView.jpg

  左边显示的是 push 之后的界面,右边显示的是模态窗口。此时,在模态窗口中点击 back 是不会有任何反应的,因为此时在 BLSubViewController 中的 navigationController 的值是 nil。那么,问题来了,当进入这个模态窗口之后我们点击 back 是无效的,我们该如何退出这个窗口呢?我们需要使 back 生效,修改 “5号”代码段

“6号”代码段

- (void)backButtonClicked:(id)sender
{
    if (self.navigationController) {
        [self.navigationController popViewControllerAnimated:YES];
    } else {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

这里使用了 ' dismissViewControllerAnimated: completion: '。至此,点击模态窗口的 back 按钮就可以相应并跳转回原先的界面了。 同时界面切换的第三点也讲完了。


接下来,我们需要了解界面切换的第一点 UIViewController 的生命周期
我们看到先在 BLSubViewController.m 文件中设置这些代码段:

#pragma mark - Memory management methods
......
#pragma mark - View's lifecycle methods
......
#pragma mark - Custom event methods
......

这样这个项目中的各个BL...ViewController.m 实现文件中的结构就是由这样三个代码块构成的。在 View's lifecycle methods 中的方法 - (void)viewDidLoad{} 和 - (void)viewDidUnload{} 其实都不止调用一次。例如:

界面1.jpg

  在上图中,下面的五个 tabbar 点击其中一个就跳转到点击方的界面,这样该界面就被 viewDidLoad 了一次。 苹果的做法很聪明,一般,只有等你点击了下面其中一个之后,系统才会调用加载那一个视图控制图。当出现内存不够的情况(例子:在点击并加载第三个视图的时候用模拟器模拟内存警告的情况),前面调用加载的 one 和 two 视图 会调用 - (void)didReceiveMemoryWarning {} 方法,接着会调用 - (void)viewDidUnload {} 的方法(现在这个方法已经不被苹果使用,当然你可以自己设置),当调用了这个方法,此方法所在的 试图控制器就会被释放(比如先打开了one->two->three, 到 three 出现内存警告,three的图片不会被释放,因为用户正在使用,不过为了内存空间 one & two 就会被释放)。然后再次点击 one 或者 two 视图 ,它们会再次调用 - (void)viewDidLoad {} 的方法。
  因此根据上面的理论结合实践的论述,当在运行app的时候,会根据不同的手机,以及手机不同的内存情况,系统有可能会不止一次的调用 - (void)viewDidLoad {} 和 - (void)viewDidUnload {} 方法。
  不过需要说明的是这个流程只在 iOS 6 之前是存在的。在 iOS 6 之后 - (void)viewDidUnload {} 是被弃用了。不过,我们花这么大的篇幅来介绍,是有助于了解 iOS 的内存是如何进行管理的。
  那现在我们的疑问是,苹果为什么会弃用这个内存管理方法呢?在听课的我也带着这个苦恼,还好苹果给出了解释:因为当我们为了内存空间 调用了 - (void)viewDidUnload {} 的方法,是将这个 view 给置 空 了, 但这其时并没有为内存留出多少空间,这个view所占用的空间其实是很小的,所以便废弃了。 好吧,似乎是很有道理,不过我也不知道是哪里更占用所谓更多的内存。 不过有一点明确的是,以前在 - (void)viewDidUnload {} 中做的事情,就需要在 - (void)didReceiveMemoryWarning {} 中进行操作。
  在 iOS6 之后,当内存释放的情况,在这个 viewDidLoad 中的view 并不会被置空,所以我们可以理解为,在那之后 - (void)viewDidLoad {} 方法只会被调用一次。

7 号代码段

#pragma mark - Memory management methods

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];

    if (self.view.window == nil) {

    }
}

- (void)dealloc
{
}

这之后,当应用收到了内存不够的警告后,需要在- (void)didReceiveMemoryWarning {}方法中做上述代码段中的判断,只有当 self.view.window 等于空的时候,才在里面输入你要释放的一些内容(图片等数据,即同时注意不要将用户在使用的界面view给释放了!)。


emsp;上面讲的是内存释放的一些流程,现在接下来再继续讲生命周期的内容,看下面一般完整的生命周期代码段:

8 号代码段

#pragma mark - View's lifecycle methods

- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

当我们在主界面选择点击 push a view 跳转到 BLSubViewController 后,会先后调用 代码块8 的前三个方法,当我们在 BLSubViewController 中点击 back 按钮,就会依次调用后两个方法,并在离开此界面的同时,可能会进行一些释放或者存储的功能,这样还会调用到 7号代码段的 - (void)dealloc{}方法。
  上述讲的就是我们所说的 UIViewController 的生命周期。


这是第一篇完整的使用 Markdown 来写的一篇笔记,同时一篇认真的笔记的完成确实是很耗费时间的,但在耗费时间的同时也发现,这样对于理解的深入是很有帮助的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,811评论 25 707
  • 在五千年的历史星河之中,有一些时光剪影里的碎片,它们穿越了不同的时空,连接了不同的时代,它们是浩瀚长河之中皎...
    我没有朗姆酒阅读 266评论 0 0
  • 那些梦想,再不做就只有后悔了 我不知道你是否有和我一样的感受,有很多想法,可是却一直拖着没做,忽然有一天,当别人和...
    影宁宁阅读 255评论 0 1
  • 生活中总有那么一个人,一件事,甚至一个微小的举动就能感动到你,也能让你找到曾经的自己。 2017年8月1日 星...
    陈筱柒阅读 400评论 6 3