遇到的问题

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

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

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

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

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

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

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

多分支NavigationController的方法

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

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

然后再继承UIStoryboardSegue,新建一个Segue,名字暂且定为ConditionShowSegue:

1
2
3
4
5
6
7
8
9
  - (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:这个方法

1
2
3
4
5
6
7
8
9
10
  - (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    if (isLogin) {
      [self performSegueWithIdentifier:@"ShowHasLogined" sender:self];
    }
    else {
      [self performSegueWithIdentifier:@"ShowLoggedIn" sender:self];
    }
  }

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
  @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来说明:

转载于:https://blog.51cto.com/ljianbing/1949175

基于Storyboard创建多分支NavigationController的方法相关推荐

  1. ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法

    ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法 一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类 ...

  2. Git创建本地分支并拉取远程分支

    一.查看远程分支 1.使用如下git命令查看所有远程分支: git branch -r 2.查看远程和本地所有分支: git branch -a 3.查看本地分支: git branch 注意:在输出 ...

  3. 模板会有多层镜像_创建镜像的方法有三种:基于已有镜像的容器创建、基于本地模板导入、基于Dockerfile创建,本博文讲解前两种。基于已有镜像的容器创建该方法是使用docke...

    创建镜像的方法有三种:基于已有镜像的容器创建.基于本地模板导入.基于Dockerfile创建,本博文讲解前两种. 基于已有镜像的容器创建 该方法是使用docker commit命令,其命令格式为: d ...

  4. git idea创建新分支,获取/合并主支代码的2个方法

    其他sql格式也在更新中,可直接查看这个系列,要是没有你需要的格式,可在评论或私信我 个人目录 获取主支代码的2个方法 1,创建一个分支,获取主支的所有代码(场景:我需要一个自己的分支进行编写模块) ...

  5. git基于远程分支创建本地分支

    git基于远程分支创建本地分支 1.首先 git branch -a 查看所有的分支 2.使用 git checkout -b 本地分支名 远程分支名 https://blog.csdn.net/no ...

  6. 【Git技术】IDEA配置git及对项目创建git分支的方法

    目录 1. 常见错误 2.IDEA配置git 3. 克隆GitHub上的项目源码 4. 创建git分支dev 1. 常见错误 Git安装在本地.并建立本地仓库且与远程Github账号关联后,想要与ID ...

  7. git基于远程分支创建新分支

    步骤一:基于远程分支创建本地新分支,并切换到新分支 git checkout -b 要创建的分支名 origin/要基于远程的分支 步骤二:注意!!! 需要先把分支推送到远程,不然提交记录会提交到基于 ...

  8. 基于SCL语言的模拟量平均值滤波FB库功能介绍及创建FB库的具体方法

    基于SCL语言的模拟量平均值滤波FB库功能介绍及创建FB库的具体方法 FB库功能说明: 可对模拟量进行平均值滤波处理,某些从现场采集的模拟量信号在传输过程中易出现干扰,可能导致数据失真,使用该FB库可 ...

  9. 基于qml创建最简单的图像处理程序(1)-基于qml创建界面

    <基于qml创建最简单的图像处理程序>系列课程及配套代码 基于qml创建最简单的图像处理程序(1)-基于qml创建界面 http://www.cnblogs.com/jsxyhelu/p/ ...

最新文章

  1. 【算力大放送2】GPU 专属服务器使用教程!!!
  2. PHP利用CURL_MULTI实现多线程
  3. linux docker 权限划分介绍 capabilities
  4. (1 24) 3 java代码_算24点 java代码
  5. 扫描仪图标无法显示计算机,win7“我的电脑”中不显示扫描仪和摄像头的原因和解决方法...
  6. 数百万台车联网设备同时在线 0 故障,中瑞集团的云原生探索之路
  7. 文档过期打不开怎么办_4 个超实用金山文档小技巧,很强大也很简单,赶紧收藏!...
  8. keil debug如何在watch直接修改变量值_python日志记录系列教程,内置logging模块(一),直接使用logging模块的基础日志记录
  9. 6-6 求二叉树高度 (15 分)
  10. SenchaTouch中出现数据覆盖 以及 “Cannot call method 'setData' of nul”l错误的可能原因
  11. 23种设计模式-备忘录模式
  12. python keras_用Python/Keras/Flask/Docker在Kubernetes上部署深度学习模型
  13. MyBatis缓存介绍
  14. 淘宝API接口:item_search - 按关键字搜索淘宝商品
  15. FaceBook流程到底应该如何?
  16. 学生机房虚拟化(十二)搭建Clonezilla SE
  17. MatConvNet的excise 3改为网络配置文件形式
  18. 被遗忘的设计模式——空对象模式(转载)
  19. 删除文本中重复的单词
  20. 这个IDEA插件可以帮你少写30%的代码

热门文章

  1. vbscript input select 添加个option根据value值到指定位置--相当于排序
  2. js实现的时间轴效果
  3. 写一个ArrayList类的动态代理类
  4. 对大龄程序员的五大误解
  5. Attention! .net 持久层正式发布 :Noebe
  6. 用命令行查看局域网的其他在线的ip
  7. php计算有多少页,PHP 计算页面执行时间
  8. 如何从 Ubuntu 中彻底卸载 Google Chrome
  9. 基于Redis实现一个分布式锁
  10. 三种云存储加密的方法