Swift Router 页面跳转路由,组件解耦

Router

为什么要用到Router去做跳转:解耦、方便

像底下这种代码可能写了很多很多遍了,尤其是在项目中某个页面入口很多的情况下。

let xx = XX()

...

let vc = XXXViewController(xx:xxx)
self.navigationController?.pushViewController(vc, animated: true)

尤其是公司要开发多个项目,对模块进行了拆分,组件化的模式需要中间一个Router去决定跳转到那个模块的页面,而不是在每个页面都import XX 耦合非常严重。

浏览了下GitHub上的两个库,都不是很满意

  • Router 比较Swifty,但是耦合比较严重,实现了很多暂时不需要的功能,每个VC需要将自己当成字符串告诉Router , 还要告诉当前的navigation , 使用了NSClassFromString根据字符创建的 AnyClass 。比较繁琐-- 但是还有很好的思想可以借鉴的
  • FNUrlRoute 通过url形式跳转,看起来挺不错,仔细看下代码,首先AppDelegate要先用字符串和VC进行映射,每个VC要传入[String:AnyObject]? 进行初始化,这个把VC的创建都限制死了。绝对用不了呀,还有那么多人star ...

说完他们的不足,首先来看下我们这个Router设计要求

  • 解耦:调用者不知道VC的名字
  • 不要用字符串,字符串容易出错
  • 不能限制初始化方法
  • 调用者应该非常简洁

那么不使用字符串很容易想到就是用枚举来替代,枚举中也可能映射VC呀,而且不用在AppDelegate中注册,不能限制初始化方法我们就用params字典去映射 Router 里面的方式 感觉比较好 , 自己肯定是知道自己怎么初始化的, 用协议的方式比用强迫字典初始化好很多

public typealias  RouterParameter = [String: Any]
public protocol Routable {
  /**
   类的初始化方法
   - params 传参字典
   */
  static func initWithParams(params: RouterParameter?) -> UIViewController
}

我们跳转只需要知道哪个VC要传的参数,这个都交给枚举就可以了,为了项目路径映射和跳转解耦,用一个协议

public protocol RouterPathable {
  var any: AnyClass { get }
  var params: RouterParameter? { get }
}

其他就交给跳转了

open class func open(_ path:RouterPathable , present: Bool = false , animated: Bool = true , presentComplete: (()->Void)? = nil){
    if let cls = path.any as? Routable.Type {
      let vc = cls.initWithParams(params: path.params)
      vc.hidesBottomBarWhenPushed = true
      let topViewController = RouterUtils.currentTopViewController()
      if topViewController?.navigationController != nil && !present {
        topViewController?.navigationController?.pushViewController(vc, animated: animated)
      }else{
        topViewController?.present(vc, animated: animated , completion: presentComplete)
      }
    }
  }

其中有用到一个工具方法是获取最上层的vc好进行跳转,具体代码可以去GitHub下载

使用: 需要使用router进行跳转的都要事先Routable 接口,调用者不需要

无参数

class AVC: UIViewController, Routable{
  override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.red
  }

  static func initWithParams(params: RouterParameter?) -> UIViewController {
    return AVC()
  }
}

有参数


struct Demo {
  var name: String
  var id: Int
}

class RVC: UIViewController {
  let demo:Demo
  init(demo:Demo) {
    self.demo = demo
    super.init(nibName: nil, bundle: nil)
  }
  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  
  override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.white
    navigationItem.title = demo.name
  }
}

extension RVC: Routable {
  static func initWithParams(params: RouterParameter?) -> UIViewController {
    guard let demo = params?["demo"] as? Demo else {
      fatalError("params is wrong")
    }
    let rvc = RVC(demo: demo)
    return rvc
  }
}

路径映射:

比如上面的vc都是其他模块的,那么只有这个映射的枚举需要引入其他模块,调用者不需要 , 下面展示三个vc的路径映射

enum RouterPath: RouterPathable {
  case avc
  case bvc(String)
  case rvc(Demo)
  
  var any: AnyClass {
    switch self {
    case .avc:
      return AVC.self
    case .bvc:
      return BVC.self
    case .rvc:
      return RVC.self
    }
  }
  
  var params: RouterParameter? {
    switch self {
    case .bvc(let name):
      return ["name":name]
    case .rvc(let demo):
      return ["demo":demo]
    default:
      return nil
    }
  }
}

只要实现 RouterPathable 都可以 ,如果需要映射的vc特别多 , 也可以分组管理。

调用者就很方便了

Router.open(RouterPath.avc)
let demo = Demo(name: "RVC title", id: 1)
Router.open(RouterPath.rvc(demo))

或者present

Router.open(RouterPath.bvc("BVC title"), present: true)

项目地址: SwiftyRouter

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

推荐阅读更多精彩内容