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

来源:互联网 发布:身份证登记软件下载 编辑:程序博客网 时间:2024/05/17 12:24

原文地址:http://www.jianshu.com/p/4ba2db91030b

为什么要用到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



作者:大石头布
链接:http://www.jianshu.com/p/4ba2db91030b
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。