iOS重构之面向协议编程实践

最近一段时间都在进行iOS客户端的重构,参考了许多iOS重构方面的资料,在重构的过程中也遇到一些困难,同时总结了不少经验,在这里和大家分享一下。这将会是一个系列的文章,每一篇文章都会从一个具体的、普遍性的问题出发,然后分析和解决这个问题。

插一句,软件开发本身是一件工程化的事情,虽然有一些理论上的指导和支持,但终归还是要从实际项目中出发,找到适合项目本身的最优解。我在这里提到的一些实践不一定适合每一个项目,甚至在某些情况下不适用,所以欢迎大家多多讨论交流,我们的终极目标都是写出具有可读性、可维护性、可拓展性的高质量代码。

问题:如何管理界面跳转的代码

回想一下你的项目中,大部分界面跳转的代码是写在哪里的?最简单方便的,直接写在ViewController中。这种方式很好理解,因为ViewController原生就提供了界面跳转的方法prsentVC/pushToVC。
随着项目逐渐复杂,你可能会发现,有一些VC可以从很多不同的VC跳转而来,如果按照原来的方式,就会有很多界面跳转代码的重复。于是我们可能会创建一个XXRouter的类,把跳转到XXViewController的代码提取出来,放到XXRouter中管理。

class XXRouter {
  var newVC:XXViewController {
    // 或者从Storyboard/Xib创建
    return XXViewController()
  }
  func presentXXVC(_ fromVC:UIViewController){
    let xxVC = newVC
    //XXViewController初始化
    vc.present(xxVC)
  }
}

于是,在其他需要跳转到XXViewController的VC中,只需要新建一个XXRouter,调用router.presentXXVC()就可以实现界面跳转,也做到了统一管理。

class MyViewController:UIViewController {
  fileprivate var router = XXRouter()
  func someFunc() {
    // do something 
    router.presentXXVC()
  }
}

这种方式已经能满足我们大部分的要求了,只不过每次都需要创建一个Router实例,当然也可以使用单例。
其实我们可以借助Swift的协议扩展Protocol Extension,可以把Router的实现变得更加直观和优雅

协议扩展Router模式

Swift相比其他OOP语言的一个比较大的特点就是面向协议Protocol Oriented,理论知识这里就不在赘述了,给一个苹果的官方文档的链接Protocol-Oriented Programming in Swift
下面就是我们的实践,这次我们使用protocol来处理我们的界面跳转的代码

protocol XXRouter {}
extension XXRouter {
  var newVC:XXViewController {
    // 或者从Storyboard/Xib创建
    return XXViewController()
  }
  func presentXXVC(_ fromVC:UIViewController){
    let xxVC = newVC
    //XXViewController初始化
    vc.present(xxVC)
  }
}

看起来和之前的实现几乎一模一样,但是在VC中我们就不需要创建XXRouter的实例,而是直接让ViewController实现我们的XXRouter

extension MyViewController:XXRouter{}
class MyViewController:UIViewController {
  func someFunc() {
    // do something 
    self.presentXXVC(self)
  }
}

这种方式还有一个好处就是可以很直观的看到界面间的跳转关系,尤其是一个界面可以跳转到不同界面的情况,比如

extension MyViewController:XXRouter,YYRouter,ZZRouter{}
class MyViewController:UIViewController{}

上面的代码几乎达到了代码即文档MyViewController这个界面,可以跳转到XX、YY和ZZ三个ViewController。
更进一步,借助extensionwhere条件扩展,我们还可以省略掉fromVC呢!

protocol XXRouter {}
extension XXRouter where Self:UIViewController {
  var newVC:XXViewController {
    // 或者从Storyboard/Xib创建
    return XXViewController()
  }
  
  func presentXXVC(){
    let xxVC = newVC
    // XXViewController初始化
    // 直接使用self,因为where指定当前扩展的是UIViewController
    self.present(xxVC)
  }
}

这种方式修改的成本很小,只是提取和挪动界面间跳转代码,几乎不会出现什么错误,用非常小的成本很大程度提高了项目代码的可读性和可维护性。目前我们项目中的界面跳转就是用这种方式进行了重构。

其他的跳转方案

最后,再简单分析一下其他两种界面跳转的解决方案

  1. Storyboard的segue跳转
    这种方式对于Storyboard内ViewController之间的简单跳转来说十分方便,不用写一行代码。而且.storyboard文件中把一个个分离的ViewController通过图的方式有机地连接在一起,清晰得展现出了项目内ViewController跳转的路径。
    不足:
    涉及到页面之间传值或者需要做额外初始化工作的ViewController,需要在代码中实现delegate,和直接代码跳转相比没有太大差别。
    对于需要额外初始化的ViewController,把一个跳转流程分离到两个地方实现,个人觉得更加不利于维护。
  2. 模仿前端的URL Router跳转,比如MGJRouter
    这种方式受Web URL跳转方式的启发,通过注册页面为URL Scheme的方式进行跳转,比较适合Hybird应用,给跳转网页和跳转ViewController一个统一的入口,便于维护
    不足:
    额外多了注册ViewController或实现Router Protocol的操作。
    侵入性大,需要在项目初期就使用这种方式,不利于重构。

这篇文章就写到这里啦,iOS重构的文章还有挖了几个坑,近期会填完!如果各位觉得本文对你有帮助的话,请点一个喜欢,谢谢~

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

推荐阅读更多精彩内容