美文网首页
9、iOS应用界面切换(笔记知识源:Geekband &

9、iOS应用界面切换(笔记知识源:Geekband &

作者: HQ今日磨墨 | 来源:发表于2015-07-30 19:59 被阅读633次

    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 来写的一篇笔记,同时一篇认真的笔记的完成确实是很耗费时间的,但在耗费时间的同时也发现,这样对于理解的深入是很有帮助的。

    相关文章

      网友评论

          本文标题:9、iOS应用界面切换(笔记知识源:Geekband &

          本文链接:https://www.haomeiwen.com/subject/ewzmqttx.html