甘道夫
甘道夫是一个轻量级的纯Swift路由器,用于URL处理。让进入的URL找到合适的处理器。这就是甘道夫所能做的。
那么处理器是什么意思呢?
protocol Handler: class {
func convert(params:Dictionary<String, String>, queryParams: Dictionary<String, String>)
func handle()
}
如果甘道夫找到了正确的处理器,它将首先带着`params`和`queryParams`调用`convert`方法。在这个方法中,这些params可以被转换成内部属性。
接下来会调用handle()
。您可以在其中做所有的事情。比如构建一个视图控制器,将其推送或显示,或者基于传入的params进行切换,或者弹出警告窗口等。
入门
首先让我们创建一些处理器。
class ProfileHandler:Handler {
var profileID: String?
func convert(params: Dictionary<String, String>, queryParams: Dictionary<String, String>) {
profileID = queryParams["id"]
}
func handle() {
if let id = profileID {
let vc = ProfileViewController()
vc.profileID = id
navigationController.push(vc)
} else {
// present error page
}
}
}
class UserHandler:Handler {
var username: String?
func convert(params: Dictionary<String, String>, queryParams: Dictionary<String, String>) {
username = params["username"]
}
func handle() {
if let id = username {
let vc = UserFollowingViewController()
navigationController.push(vc)
}
}
}
然后使用适当的URL模式将这些处理器连接起来。
let routeTable:[String:Handler] = [
"app://profile": ProfileHandler(),
"app://user/{username}/following": UserHandler(),
]
Gandalf.instance.registerRoutingTable(routeTable, notFoundHandler: {url in print("\(url) not found")})
现在让我们处理URL!
// for test case
Gandalf.instance.handleURL(url: "app://profile?id=1024")
Gandalf.instance.handleURL(url: "app://user/limboy/following")
// usually it should be put in `AppDelegate's` method
func application(_ application: UIApplication,
open url: URL,
sourceApplication: String?,
annotation: Any) -> Bool {
// ...
Gandalf.instance.handleURL(url: url.absoluteString)
}
如果甘道夫在注册表中找到了URL的模式,目标处理器将触发,否则将调用notFoundHandler
,在那里可以显示一个自定义的视图控制器。
安装
Podfile
pod 'gandalf'
场景
推送一个viewController
例如,点击 ShopItemListViewController
中的某一项,应推送一个 DetailViewController
。可以这样实现:
let handler = DetailHandler()
handler.id = 1024
handler.handle()
DetailHandler
作为 DetailViewController
的入口/包装器,无论它是从URL传入还是内部调用,都统一处理。
因此,您不需要打开目标 ViewController,试图找出需要初始化的内容。它对 DetailViewController
来说也很有弹性,即使某些属性应该在 DetailHandler
未受影响的情况下更改。
插画风格
当Pinterest的瀑布流列表项被点击时,其模型将被传递到详情页,因此它不会一开始就是空的。但是当通过URL打开时,不会传递任何模型。这些两种情况都由 DetailHandler
处理。
class DetailHandler:Handler {
var itemModel: ItemModel?
var itemID: String?
func convert(params: Dictionary<String, String>, queryParams: Dictionary<String, String>) {
itemID = params["id"]
}
func handle() {
// opened internal
if let model = itemModel {
let vc = DetailViewController()
vc.model = itemModel
navigationController.push(vc)
return
}
// opened by url
if let id = itemID {
let vc = DetailViewController()
vc.id = itemID
navigationController.push(vc)
}
}
}
当基本模型填写完成或用户进行了某些更改时,前一个 ViewController 应该知道并相应更新。只需添加一个像 onModelUpdate()
这样的属性,当模型更新时只需调用此函数(如果它不为nil)。
路由设计
URL模式存储在一个类似树的radix中,它会首先将传入的url分割成多个部分,然后通过树逐一匹配它们。
技巧
- 为了简化事物,URL模式仅匹配到
String
。例如,app://profile/{id}
将使convert
方法中获取的params["id"]
作为String
。 - 可以将导航器注入到
Handler
的子协议中,以使其更易于导航。 - 当通过类似
?debugcode=xxx
的URL打开时,可以使用SomeHandler
作为配置处理器,开启调试模式。
联系
您可以在Twitter上关注并与我联系。如果您发现任何问题,请打开一个工单。拉取请求也热烈欢迎。
许可
本项目采用MIT许可证发布。具体信息请参见LICENSE文件。