如果遇到本文图片只展示一半的情况,多数情况下刷新一下浏览器即可

遇到的问题

我在写程序的时候碰到这样一个简单的需求,用户点击“我的XX”这样的功能时候,需要判断当前用户是否已经登录,如果已经登录了,则显示该用户的相关信息并且可以切换到更多界面:

如果没有登录,则显示登录界面并且可以选择登录还是注册:

后来继续了解到其实不止一个功能需要有这样的需求,任何需要登录后才能进行的功能,当用户点击时,都需要做这样的判断。

那我怎样才能把上述两种情况有机地结合在一起,并且能在多个地方复用呢?

当时的第一想法是在代码里根据当前用户登录还是不登录手动替换NavigationController的RootViewController,但是我目前的程序完全是基于Storyboard来写的,因此界面的流转关系是完全体现在Storyboard上的。我想这个功能也能继续维持这样的状态,能在Storyboard上清晰地体现出来(这里不讨论Storyboard的优劣,只是想说明工程代码的表现形式要一致)。

由于年少不懂事,当时以为只要做出下图的这种关系就可以了,当然很快就发现这是不可能的

后来发现其实NavigationController内部也是实现了类似于ContainerViewController的机制(可能需翻墙),所以只需要替换ContainerViewController的内容,自然也就替换了相应的界面。

多分支NavigationController的方法

根据上述的讨论,具体的方案已经呼之欲出了(关于具体的自定义ContainerViewController的技术细节就不再阐述了,上面的链接已经解释的很清楚了,这里主要是讨论如何使之应用到我们的场景中)。

我是先自己在Storyboard上建立一个RootViewController,名字暂且定为ConditionContainerViewController(具体代码后面会介绍到),如下图:

然后再继承UIStoryboardSegue,新建一个Segue,名字暂且定为ConditionShowSegue,代码很简单只要在@@implementation中写下如下这个函数:

  - (void)perform {
UIViewController *srcVC = self.sourceViewController;
UIViewController *destVC = self.destinationViewController; [srcVC addChildViewController:destVC];
[srcVC.view addSubview:destVC.view];
destVC.view.frame = CGRectMake(0, 0, CGRectGetWidth(srcVC.view.frame), CGRectGetHeight(srcVC.view.frame));
[destVC didMoveToParentViewController:srcVC];
}

如果上面代码暂时不能理解,请回到之前发的链接再仔细理解里面的内容(我当时也是看了好几遍,呵呵)。

随后就可以在Storyboard中使用这个Segue了,可以看到菜单里多了一种“Condition Show”:

用新的Segue来连接之前在本文一开始就展示的两段分开的业务线,使之结合在一起

然后分别定义这两个Segue的Identifier为“ShowNeedLogin”以及“ShowLoggedIn”。

接下来我们再回过头来看ConditionContainerViewController的代码,其实主要代码非常简单就是重载viewWillAppear:这个方法

  - (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated]; if (isLogin) {
[self performSegueWithIdentifier:@"ShowHasLogined" sender:self];
}
else {
[self performSegueWithIdentifier:@"ShowLoggedIn" sender:self];
}
}

isLogin这个你可以使用各种方法来实现,比如自定义一个变量或者全局有一个用户管理类来暴露一个isLogin属性等。

其实目前程序已经可以根据你当前登录的情况来自动切换展示的界面了,但是现在还有一个问题,登录成功之后又怎么跳回已经登录的界面的?只要在需要登录成功后调用如下代码:

  // 普通情况下直接调用popToRootViewControllerAnimated即可
// 然后ConditionContainerViewController会通过viewWillAppear来判断
NSArray *poppedViewcontrollers = [self popToRootViewControllerAnimated:animated];
// 但是如果是从上面那个图的Need Login这个界面返回,这个时候已经在RootViewController了
// 因此需要手动调用viewWillAppear
if (poppedViewcontrollers == nil) {
[[self.viewControllers firstObject] viewWillAppear:YES];
}

好了,接下来我们还需要一些清理代码,在ConditionContainerViewController写入以下函数:

  @property (nonatomic, strong) UIViewController *lastViewController;
... - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if (segue.destinationViewController != self.lastViewController) {
[self.lastViewController willMoveToParentViewController:nil];
[self.lastViewController.view removeFromSuperview];
[self.lastViewController removeFromParentViewController];
}
self.lastViewController = segue.destinationViewController;
}

这个清理代码应该有更好地方来写,目前我只能想到放在这里,希望大家可以给一些建议。

当然,一开始我也提到这种方法是要可以复用的,且在Storyboard上能清晰地表示出来,最后我就展示一张简单的Storyboard来说明:

基于Storyboard的创建多分支NavigationController的方法的更多相关文章

  1. git基于历史commit创建分支

    基于以前的commit创建一个分支 步骤: 1.确定需要取出版本的commit值 git log 2.基于该commit创建分支 git branch <branch name> < ...

  2. git 创建远程分支和删除 master 分支

    . . . . . 最近需要将不同的客户的代码分开管理,所以需要为这些代码分别创建分支. 目前版本库中分支结构如下: [yuhuashi@local:Project]$ git branch -a* ...

  3. git 创建branch分支

    开发者user1 负责用getopt 进行命令解析的功能,因为这个功能用到getopt 函数,于是将这个分支命名为user1/getopt.(1)确保是在开发者user1的工作区中cd /home/j ...

  4. git 创建branch分支【转】

    转自:http://www.cnblogs.com/jackluo/p/3499731.html 开发者user1 负责用getopt 进行命令解析的功能,因为这个功能用到getopt 函数,于是将这 ...

  5. git 从分支上创建一个分支

    相关连接: 创建于合并分支:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/00 ...

  6. Git创建本地分支并关联远程分支

    创建本地分支git branch 分支名 例如:git branch dev,这条命令是基于当前分支创建的本地分支,假设当前分支是master(远程分支),则是基于master分支创建的本地分支dev ...

  7. Git创建本地分支并关联远程分支(二)

    创建本地分支git branch 分支名 例如:git branch dev,这条命令是基于当前分支创建的本地分支,假设当前分支是master(远程分支),则是基于master分支创建的本地分支dev ...

  8. git使用笔记-git项目的建立及配置、创建子分支及独立分支、分支重命名

    一.git的基本使用 1.下载安装git (略) 2.配置gitconfig 配置内容:(主要是你的git的账户信息,提交命令的别名) 3.配置git公钥(输入$ ssh-keygen -t rsa ...

  9. git创建本地分支,推送到远程

    创建本地分支git branch 分支名 例如:git branch dev,这条命令是基于当前分支创建的本地分支,假设当前分支是master(远程分支),则是基于master分支创建的本地分支dev ...

随机推荐

  1. Java基础语法实例(1)——实习第一天

    来到广州实习的第一天,我选择的是JavaEE,因为以后的方向是Java,所以就选择了它.感觉有一段时间没有接触Java了.趁此机会好好努力,将基础巩固好. Java输入及循环,判断,字符转换,数组定义 ...

  2. zjoi2018day1 游记

    3.18 这一天乘车来到衢州,这已经是第四次了,来衢州二中考过两次普及,一次提高,都不是特别好. 到了以后先去了宾馆,是在帝京,和NOIP一样的酒店,连房间都是隔壁,然后一进去就连上了隔壁的WIFI ...

  3. PEP8特性

    Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格.这样就易于阅读, ...

  4. BZOJ 4261: 建设游乐场

    4261: 建设游乐场 Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 38  Solved: 16[Submit][Status][Discuss] ...

  5. 用户空间缺页异常pte_handle_fault()分析--(上)【转】

    转自:http://blog.csdn.net/vanbreaker/article/details/7881206 版权声明:本文为博主原创文章,未经博主允许不得转载. 前面简单的分析了内核处理用户 ...

  6. 将本地访问ip映射成域名

    通过修改以下地址 C:\WINDOWS\system32\drivers\etc\hosts 加进你自己的如: 192.168.1.101  www.helloworld.com 配置nginx代理u ...

  7. 【linux高级程序设计】(第九章)进程间通信-管道 3

    有名管道 无名管道和有名管道: 1. 管道是特殊类型的文件,在满足先入先出的原则写可以读写,不能定位读写位置. 2.管道是单向的. 3.无名管道阻塞于读写位置,而有名管道阻塞在创建位置. 4.无名管道 ...

  8. Javascript中call、apply函数浅析

    call/apply函数作用其实就是改变this的取值,有一句话是:谁调用的这个方法那方法里的this就是指谁,而有时我们会需要改变this值,所以call/apply就能派上用场. 下面我写个方法来 ...

  9. Jquery学习之路(二) 实现table样式的设定

    上一篇jquery实现checkbox的全选,得到了一些朋友的建议,其中插件的定义我的确不太清楚,也闹了个笑话,有些朋友建议我去看<锋利的Jquery>,说实话正在看了.由于正在学习中,我 ...

  10. ACM阶段总结(2016.10.07-2016.11.09)

    来这里也有一段时间了…… 总感觉自己练得不是很有效. 最近的一些行动就是不断做比赛,然后不停地补,但是感觉这样像只无头苍蝇,没有效果,学不到什么真正的东西. 最近开始打算补专题,做做codeforce ...