iOS界面跳转以及一些优化方案

原文地址: http://blog.startry.com/2016/02/14/Think-Of-UIViewController-Switch/

iOS界面跳转的一些优化方案

App应用程序开发, 界面跳转是基础中的基础, 几乎没有一个App是用不到界面跳转的, 那么怎么样去书写界面跳转代码才是比较合理的呢?

大家可能在想跳转无非就2种方式, 能有什么内容? 其实并不是这样子的, 对于研发老手来说, 大型应用几乎都是利用URLScheme进行全方位的解决方案; 对于研发新手来说, 他们可能并没有遇到多路口界面跳转的瓶颈, 只会使用一些常用跳转, 并不会意识到界面跳转潜在的一些问题, 甚至无法严格区分Present和Push的操作区别~

本文将针对界面跳转提出一些优化解决方案~

常用跳转方式

iOS常用的跳转方式只有两种PresentPush。Push和Present最直观的区别是默认的转场效果, Present的默认转场效果是自下而上的, Push的转场效果是自右到左的。Push往往需要搭配UINavigationController来使用。

Push跳转使用示意:

1

UIViewController *nextViewController = [[UIViewController alloc] init];nextViewController.title = @"第二个界面";[self.navigationController pushViewController:nextViewController animated:YES];

Present跳转使用示意:

1

UIViewController *nextViewController = [[UIViewController alloc] init];nextViewController.title = @"第二个界面";[self presentViewController:nextViewContrller animated:YES completed:nil];

在大部分情况下, iOS研发者都在滥用Push的跳转方式, 往往一个App仅仅包含一个UINavigationController。产生滥用的原因是因为Present的跳转太过难于定制转场效果, 仅仅只能使用系统提供的4种打开方式。

在满足产品要求的前提下, 其实可以基于模块内跳转模块外跳转的思量去考虑采用Present的方式还是Push的方式去跳转界面。

PS: 还有一种界面切换方式是利用ChildViewController, 进行独立界面的控制。需要高度定制的界面可以采用这种方式, 例如基于地图或者相机的应用。基于ChildViewController的方式内容篇幅太长, 在本文就暂时不介绍了, 以后再补充~

常用跳转方式瓶颈

常用的跳转方式其实已经几乎可以满足我们所有的跳转, 但是欠缺一层业务层次的高层级封装

举一个实际使用场景, 某App支持4种页面打开方式:

Push推送

App外部网页打开

App内部网页打开

应用内点击打开

这四种方式均跳转到DetailViewController界面。普通的跳转依然可以满足该场景, 最简单的解决方案是在四个不同的地方都写一个独立的界面打开逻辑。

作为一名业务模块人才, 如此不复用代码合理么? 作为一名App架构师, 如此冗余四份入口代码合适么?

如果您觉得不合适, 那自然需要去抽离代码到统一的地方去书写一套统一的管理逻辑; 如果您觉得合适, 那么您会设想什么方案去根据外部网页以及Push内容去转化代码至普通跳转代码呢?

URLScheme解决方案

我们先根据前面提到的四种场景进行场景分析:

外部网页场景:

只能使用iOS自带的URLScheme的方式去打开App, 然后通过AppDelegate中事件去获取对应的URL进行匹配

Push推送场景:

在extra字段中定义个链接字段, 链接字段是个字符串或者数字代号, 用于在AppDelegate中事件去获取对应的代号进行匹配; 既然代码是自定义的, 那自然可以定义成一个URL了

内部网页场景

熟悉iOS WebView开发的童鞋们都知道, UIWebView的JS交互本质上是通过截获URL请求去实现的, 那么既然是传递URL地址, 就可以和外部网页使用相关的方式, 只不过在不同的位置进行对应的URL匹配

应用内点击打开

可以采用普通打开方式, 也可以通过一个抽离的URLScheme匹配器去匹配打开

根据上述四个场景, 我们可以发现, 解决上述四个应用场景, 我们需要的是引入一个抽离的URLScheme匹配器去匹配打开轮转界面~

利用URLScheme的方式进行一层封装, 几乎可以完美解决多入口打开App的逻辑复用问题。

PS: 一般情况下, URLScheme的抽离器不需要自己封装, 可以使用开源现成的, 很少场景需要高度定制。

开源URLScheme解决方案:

RoutableAndroid和iOS均支持的一款权威的应用内URL跳转路由, 几乎可以满足所有需求

代码切入性比较低, 没有冗余的继承封装。

可以指定NavigationController, 方便定制ChildController的跳转

可以多个Router组合使用, 灵活性高

urlmananger国内技术问题网站segmentfault.com开发者抽离的一个跳转器

需要嵌入继承和绑定使用NavigationController, 架构设计层级嵌入性很高, 没有Routable合理

无法多个组合使用, 灵活性没有Routable高

封装层次高, 快速使用可以采用

个人比较倾向使用Routable, 因为并没有在架构上对代码进行嵌入, 比较符合开发者口味~

以Routable作为示例, 本文可以通过如下代码在App启动的时候就提前注册(PS: Push点击打开执行Optional参数之前注册)

1

[[Routable sharedRouter] map:@"detail/:id" toController:[DetailController class]];

假设您的App URLScheme前缀为demo123, 您只需要在上述四个场景分别传递demo123://detail/88过来即可。88只是示例的一个随意乱写的id编号, 作为Restful分格的参数进行处理。

URLScheme些许问题

URLScheme进行界面跳转的解决方案也不是完美的, 个人开发时候遇到最大的问题就是传值问题

怎么传递对象值

URLScheme原则上不支持传递复杂的对象, 通过URLScheme方式打开的界面理论上每个界面都相对保持逻辑独立(逻辑独立的代价往往是牺牲细微的用户体验), 逻辑独立的界面可以有更好的架构设计

通过外部URL或者Push的方式是无法传递对象的, 可以不用考虑传递对象的场景

应用内界面跳转可以根据实际场景去区分使用URLScheme的方式还是普通的方式进行界面跳转控制

怎么传递URL值

URLScheme打开的界面有时候也需要传递URL值用于对应的界面, 最常见的是打开图片管理器以及打开WebView的界面, 这种场景可以采用约定加密的方式进行处理, 对传递的URL进行URIEncode和取值时候的URIDecode。

Push长度限制

坑爹的APNs规定了Push内容的总长度不能大于255字节, 那么URLScheme的参数传递就收到限制。

最常用的解决方案是压缩字段名字和内容, 传递的字段劲量用一个单词表示, 值字段可以隐藏掉URLScheme的前缀, 只保留后缀以及参数。

还有一种通过的Push长度解决方案是, push只是触发器, 触发App请求去获取真正的内容来绕过长度限制。

传值对象

此处针对应用内跳转使用url scheme还是普通方式进行一些议论, 个人觉得一套应用里如果有两种方式跳转, 虽然灵活性高, 但是比较难以控制, 因此最好都采用一套方式跳转, 那自然是使用url scheme。那复杂传值的问题依旧无法得到解决。

有些开发者为了省时间, 直接通过类似Notification的方式或者用单例对象去维护进行值传递, 也不失为一个方法。

但是我在思考, 有没有一种相对完美的解决方案, 能够将传值问题彻底用url scheme进行传递呢?

结合本人喜欢使用的库JSONModel, 我想到了一种暴力且耗时的解决方案, 但是至少不产生耦合哈~

暴力解决方案步骤:

JSON化对象

将对象JSON字符串Base64加密

将Base64加密后的字符串作为url参数传递

接受者处理参数的时候反Base64解密

将解密后的JSON对象用模型实例化

针对暴力解决方案, 本人设想了四个自问自答:

为什么不直接Base64对象而需要将其JSON字符串话呢?

答: 为了接受者解密后的直观性。在大型App开发过程中, 解密者解析后不一定知道用哪个模型去实例化JSON字符串, 通过这种方式, 解密者可以不关心接受数据后的模型实例而自由发挥。

利用这种方式暴力解决后, url会不会很长?

答: 这种方式传递的url会超级长, 但是在应用内进行页面处理的场景, 不需要可以的去考虑url的长度。但是url的长度可能会影响解析的性能。

为什么不直接通过广播或者单例维护的方式传值?

答: 为了解耦。 大型App维护的时候, 如果一个内存对象是公用的, 是十分难以维护的, 应该尽量减少传递对象之间的耦合。

为什么需要base64加密而不直接采用uriencode的方式?

答: 为了解决模型嵌套的问题。因为一个模型里可能会嵌套另外一个模型, 当然通过JSON字符串本身可以实现模型嵌套的解决, 那可以有更加节省性能的解决方案。

本人水平有限, 此处的暴力的方式是目前本人觉得相对耦合度低并且比较好的一种解决方案。对于目前的iOS手机设备来说, 这点JSON以及解密的性能并不能影响整个App的运行, 因此采用这种方式进行暴力解决。

总结

页面轮转在小型的App并不需要针对单独进行优化设计, 但是对于上20w行代码的大型App来说, 往往都是需要针对优化的。

本文引用了市面上最通用的URLScheme的解决方案来进行页面跳转的设计优化, 并建议采用开源库Routable来进行统一管理。

根据个人在界面跳转开发中遇到的困难, 提出了几个相应的瓶颈和对应的解决方案。针对传递对象值提出了一种暴力但是耦合度比较低的解决方案。

PS: 本人水平有限, 有错误的地方还望大家及时指出~ 谢谢!

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,062评论 25 707
  • 前言: 本文转自前同事casa的博文,这篇文章是基于runtime实现的iOS组件化方案,其实iOS组件化方案基本...
    monkey01阅读 1,650评论 1 2
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,945评论 4 60
  • iOS应用架构谈 组件化方案 讨论论坛 源 简述 前几天的一个晚上在infoQ的微信群里,来自蘑菇街的Limboy...
    其实也没有阅读 1,409评论 1 9
  • iOS即时通讯,从入门到“放弃”?socket的半包,粘包与分包的问题iOS 处理socket粘包问题iOS___...
    xiari1991阅读 104评论 0 0