-
Notifications
You must be signed in to change notification settings - Fork 0
快速开始
下面的内容将告诉您如何使用该库,但基本不会涉及 "为什么这么做" 以及 "这个类型是什么意思"。
有关更多详细信息,请参见其他 wiki。有关完整的代码示例,请参阅随仓库配套的 demo(在
Examples
目录下)。
RaRouter
基于面向协议原则进行开发。在正式开始之前,希望本图能让您对 RaRouter
各协议之间的组织关系有一个初步的了解:
RaRouter
默认提供以下三种路由操作:
-
do
: 执行某些操作:
let router = "rakuyo://moduleA/do/something"
_ = Router<Global>.do(router, param: ("参数1", 2))
-
get
:执行某些操作,并获得其返回值:
let router = "rakuyo://moduleA/calculate/frame"
let result = Router<Global>.get(of: String.self, from: router, param: "参数")
switch result {
case .success(let string):
print(string)
case .failure(let error):
print(error)
}
// Or use default values
let string = Router<Global>.get(of: String.self, from: router, param: "参数").get(default: "defaultString")
// When an error occurs, "defaultString" will be printed
print(string)
-
viewController
:执行某些操作,并获得其返回的UIViewController
子类:
let router = "rakuyo://moduleA/create"
let result = Router<Global>.viewController(from: router)
switch result {
case .success(let controller):
print(controller) // `UIViewController`
case .failure(let error):
print(error)
}
-
Router
类型是RaRouter
提供的一个遵守RaRouter
协议的默认类型,用以执行、注册路由。它的声明请参考:Router。 -
关于
RaRouter
协议的相关内容,请参考 wiki 或随仓库配套的 demo。 -
Router
类型需要一个泛型,该泛型代表着路由所属的模块。而Global
泛型代表着 “全局模块”。相关的概念及内容将在 进阶教程 中详细介绍。 -
对于
param
参数,其为Any?
类型,默认为nil
。这意味着您可以传递任何您想要的参数,并且不受任何的限制。例如在上面
do
的示例中,传入了一个(String, Int)
类型的元组作为参数,而在get
示例中只传入了一个String
。到了viewController
,因为从编码上来说"rakuyo://moduleA/create"
不需要任何参数(假如编写了那些代码),所以可以直接省略param
参数。 -
viewController
操作没有像get
操作一样,在方法中添加type
参数用以转换类型。因为
Controller
的定义往往在核心组件中,而RaRouter
要求路由组件独立且尽可能的不去依赖其他组件。所以在一般情况下,在调用viewController
方法时,用户是无法获取ViewController
的真实类型的。而执行
get
操作时,因为我们可以将模型类定义在路由组件,所以设计了type
参数,并提供了转换失败时的相关错误。
我们还可以再优化一下上面的代码,例如封装一下 router
路由字符串:
RaRouter
提供了 ModuleRouter
与 RouterTableProtocol
协议,用户可以借助这两个协议定义一个模块:
public enum ModuleA: ModuleRouter {
public typealias Table = RouterTable
public enum RouterTable: String, RouterTableProtocol {
public var url: String { rawValue }
case create = "rakuyo://moduleA/create"
case doSomething = "rakuyo://moduleA/do/something"
case calculateFrame = "rakuyo://moduleA/calculate/frame"
}
}
紧接着,还可以再借助 RaRouter
协议的泛型 Module
,封装路由的执行过程:
其中,
DoResult
、GetResult<T>
以及ViewControllerResult
的详细说明请参考 wiki 或随仓库配套的 demo。
public extension Router where Module == ModuleA {
static func doSomething(start: Date, end: Date) -> DoResult {
return Router.do(.doSomething, param: (start, end))
}
static func calculateFrame(with screenWidth: CGFloat) -> GetResult<CGRect> {
return Router.get(of: CGRect.self, from: .calculateFrame, param: screenWidth)
}
static func create() -> ViewControllerResult {
return Router.viewController(from: .create)
}
}
当我们再执行 执行路由 一节的示例代码时,就可以调用封装好的方法:
// for `do`
_ = Router<ModuleA>.doSomething(start: Date(), end: Date())
// for `get`
if case let .success(frame) = Router<ModuleA>.calculateFrame(with: 375) { }
// for `viewController`
if case let .success(controller) = Router<ModuleA>.create() { }
最后,我们需要注册刚刚定义好的路由。
对于默认提供的三种操作,每种操作都有不同的注册方法。而它们的区别在于闭包的返回值不同:
do
其闭包的返回值规定为 DoResult
(Result<Void, RouterError>
):
Router<Global>.register(for: "your router") { (url, value) -> DoResult in
// do something
return .success(())
}
get
其闭包的返回值规定为 GetResult<AnyResult>
(Result<Any?, RouterError>
):
Router<Global>.register(for: "your router") { (url, value) -> GetResult<AnyResult> in
return .success(.zero)
}
viewController
其闭包的返回值规定为 ViewControllerResult
(Result<UIViewController, RouterError>
):
Router<Global>.register(for: "your router") { (url, value) -> ViewControllerResult in
return .success(UIViewController()) // your controller
}
对于在 封装 一节中编写的的示例,其对应的注册代码如下所示:
// Need to declare a class and follow the `RouterRegister` protocol
private class ModuleARegister: RouterRegister {
static func register() {
let router = Router<ModuleA>.self
router.register(for: .doSomething) { (url, value) -> DoResult in
guard let param = value as? (start: Date, end: Date) else {
return .failure(.parameterError(url: url, parameter: value))
}
print("We are doing these things from \(param.start) to \(param.end)")
return .success(())
}
router.register(for: .calculateFrame) { (url, value) -> GetResult<AnyResult> in
guard let screenWidth = value as? CGFloat else {
return .failure(.parameterError(url: url, parameter: value))
}
return .success(CGRect(x: 0, y: 0, width: screenWidth * 0.25, height: screenWidth))
}
router.register(for: .create) { (url, value) -> ViewControllerResult in
return .success(UIViewController())
}
}
}
最后的最后,需要在 AppDelegate.swift
的 application(_:, didFinishLaunchingWithOptions:)
方法中执行注册代码:
// In AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// some codes with higher priority than registered routes
// initialize modules
Router<Modules>.initialize()
// some other code ..
}