iOS(Swift) 路由设计二

2023-02-26 今天难得的一个好天气,一整天阳光暖洋洋,精力十足,整理框架时,对路由一些小想法,于是花了一整天,把整个路由组件做成了pod,抽了出来.

上一篇路由讲了个当时随手写的一个框架,但写完后项目没怎么用,后面因为事情太多,渐渐也就忘了,这次重新整理了一下思路,对路由重新设计了一番.

架构

|____Classes
| |____GetRouter.swift
| |____GetRouterHandlerSource.swift
| |____.gitkeep
| |____ReplaceMe.swift
| |____GetRouterMiddleware.swift
| |____GetRouterName.swift
| |____GetRouterHandler.swift
|____Assets
| |____.gitkeep

路由设计

路由分远程路由和本地路由,我们需要做的是统一,远程路由适用与banner跳转,js交互操作等等情况,一般来说是string执行的路由跳转,本地路由需要规定要,一个页面的跳转,最好走唯一的路由,好处就是封装,低耦合,A页面理论上是不应该import B页面的,还有就是埋点参数上报等等,统一路径.

流程

  • 远程路由
    urlStirng->encoding->parse解析路由,合并参数->匹配本地路由->执行跳转
  • 本地路由
    匹配本地路由->执行跳转

GetRouter

远程路由与本地路由解析的流程文件后,解析完成后交给GetRougerHandler执行

GetRougerHandler

匹配路由名相同的GetPage 执行中间件拦截, 执行跳转

GetRouterMiddleware中间件拦截

中间件用于公共拦截方式,举例说明,我们如果要想跳转vip直播间,我们需要前置判断当前登录者是不是vip,当前vip直播间是否正在直播,一个是同步就可以判断出当前用户vip状态,一个需要实时请求后端直播状态接口等.
传统方式中,我们可能需要通用写个判断

// 判断vip
guard User.isVip else {
return 
}
// 判断直播状态
RequestLiveStatus {
  jumpLive()
}

这样写不太优雅, 所以我增加了同步拦截与异步拦截(注意,中间件的环境在iOS13以上处于异步线程,执行UI操作,吐丝重定向等请回到主线程执行)

open class GetRouterMiddleware {
    /// 优先级
    let priority: Int
    
    public init(priority: Int) {
        self.priority = priority
    }
    /// 处理返回结果
    /// - Returns: true: 允许通过 false: 禁止
    open func handler(routeName: GetRouterName, params: GetDict?) -> Bool { true }
    
    @available(iOS 13.0.0, *)
    /// 异步中间件, 注意如果想要在此出重定向路由,注意要回到mainThread
    /// - Parameter routeName: 路由名
    /// - Returns: true: 允许通过 false: 禁止
    open func handlerAsync(routeName: GetRouterName, params: GetDict?) async throws -> Bool { true }
}

这里注意一下,异步拦截是iOS13以上可用,需要自行构造一个async任务(相关只是可以参考await async 构造async),demo也有相关示例,使用起来也很方便

GetPage

注册路由时包装的路由匹配信息,包括中间件和行为.

GetRouterHandlerSource

提供GetPage的source来源

GetRouterName路由名设计

原先我们设计的路由名是这样的

enum GetRouterName: String {
    // MARK: - --------------------------------------公共
    case http = "http"
    case https = "https"
    // MARK: - --------------------------------------发现
    
    // MARK: - --------------------------------------社区
    case community_post_detail = "community_post_detail"
    // MARK: - --------------------------------------个人
    
    // MARK: - --------------------------------------我的
    case mine_setting = "mine_setting"
    case mine_complete = "mine_complete"
    // MARK: - --------------------------------------帖子
    case post_detail = "post_detail"
}

很简单,很易懂,但是有缺点

  • enum可以在switch中可以枚举掉所有的选项,保证我们不会漏掉任何路由名,但是,enum无法写成extension,也就是说,我们必须把所有名卸载一个文件里,这样对模块化是不好的,我希望使用的场景是我每个模块去注册这个路由,然后提供我模块的模块名和路由处理选项,这样就可以做到单独开发自己的选项
  • string不是类型,在本地调用中,我们不可避免的会出现必须强制带类名的方式,写起来就不是那么清爽,例如Router.to(GetRouterName.mine_setting),我想要的是Router.to(.mine_setting)
    所以,利用swift的语法特点,我修改成这种写法
/// 路由列表容器
public struct GetRouterNames {}

/// 路由列表
public struct GetRouterName: RawRepresentable,
                      ExpressibleByStringLiteral,
                      Hashable {
    
    public var rawValue: String
    
    public init(rawValue: String) {
        self.rawValue = rawValue
    }
    
    public init(stringLiteral value: StringLiteralType) {
        self.rawValue = value
    }
    
    public var hashValue: Int {
        rawValue.hashValue
    }
}

这里写了一个类型GetRouterName,利用swift字面量,可以达到这种定义路由名的效果

//  GetRouter+Home.swift
//  quick
//
//  Created by suyikun on 2023/2/25.
//

import Foundation

extension GetRouterNames {
    /// 发现列表
    static let discover: GetRouterName = "/discover/list"
    /// 发现页详情
    static let discoverDetail: GetRouterName = "/discover/detail"
}

虽然,我们损失了enum强制枚举所有枚举的效果,但是,我们收获了模块化路由名+路由名类型的优点

使用示例




注意事项: 获取参数时,远程路由获取的value是string类型,需要在写代码时考虑兼容转换

自己在业务跳转方面,做好兼容即可, 例如下图这样处理

PS

在我看来,路由设计应该是可以纯粹的解耦合的,他跟业务的跳转没有一点关系,只是一些规则的解析,
总结一下,回顾了下整个路由设计,一天的收获满满,如果你们喜欢我的文章,或者对路由设计有什么批评建议意见,希望可以点赞留言
最后留一下git地址: 戳这前往

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

推荐阅读更多精彩内容