[{"data":1,"prerenderedAt":4382},["ShallowReactive",2],{"navigation_docs":3,"-ios-routing":173,"-ios-routing-surround":4377},[4,22,29,36,107,138,145,161],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"博客","i-lucide-pen-line","\u002Fblog","0.blog",[10,12,17],{"title":5,"path":7,"stem":11,"icon":6},"0.blog\u002Findex",{"title":13,"path":14,"stem":15,"icon":16},"创建基于 UIKit 的原生 iOS 项目","\u002Fblog\u002Fcreate-uikit-ios-project","0.blog\u002F01.create-uikit-ios-project","i-lucide-app-window",{"title":18,"path":19,"stem":20,"icon":21},"Lockify：把账号和密码留在自己的手机里","\u002Fblog\u002Flockify","0.blog\u002F02.lockify","i-lucide-lock",{"title":23,"path":24,"stem":25,"children":26,"icon":28},"年度总结","\u002Fannual-review","1.annual-review\u002Findex",[27],{"title":23,"path":24,"stem":25,"icon":28},"i-lucide-git-commit",{"title":30,"path":31,"stem":32,"children":33,"icon":35},"故事","\u002Fstories","2.stories\u002Findex",[34],{"title":30,"path":31,"stem":32,"icon":35},"i-lucide-feather",{"title":37,"icon":38,"path":39,"stem":40,"children":41},"Android","i-simple-icons-android","\u002Fandroid","3.android",[42,44,49],{"title":37,"path":39,"stem":43,"icon":38},"3.android\u002Findex",{"title":45,"path":46,"stem":47,"icon":48},"初探Navigation","\u002Fandroid\u002Fcompose-navigation","3.android\u002F01.compose-navigation","i-lucide-route",{"title":50,"icon":51,"path":52,"stem":53,"children":54},"安卓代码加固","i-lucide-shield","\u002Fandroid\u002Fhidden-hardening","3.android\u002F02.hidden-hardening\u002Findex",[55,58,62,67,72,77,82,87,92,97,102],{"title":56,"path":52,"stem":53,"icon":57},"安卓代码加固：总览","i-lucide-map",{"title":59,"path":60,"stem":61,"icon":21},"安卓代码加固（1）：加密DEX","\u002Fandroid\u002Fhidden-hardening\u002Fencrypt-dex","3.android\u002F02.hidden-hardening\u002F01.encrypt-dex",{"title":63,"path":64,"stem":65,"icon":66},"安卓代码加固（2）：Native解密","\u002Fandroid\u002Fhidden-hardening\u002Fnative-decrypt","3.android\u002F02.hidden-hardening\u002F02.native-decrypt","i-lucide-cpu",{"title":68,"path":69,"stem":70,"icon":71},"安卓代码加固（3）：内存加载","\u002Fandroid\u002Fhidden-hardening\u002Fmemory-load","3.android\u002F02.hidden-hardening\u002F03.memory-load","i-lucide-memory-stick",{"title":73,"path":74,"stem":75,"icon":76},"安卓代码加固（4）：指令分发","\u002Fandroid\u002Fhidden-hardening\u002Fopcode-dispatch","3.android\u002F02.hidden-hardening\u002F04.opcode-dispatch","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"安卓代码加固（5）：XOR混淆","\u002Fandroid\u002Fhidden-hardening\u002Fxor-obfuscate","3.android\u002F02.hidden-hardening\u002F05.xor-obfuscate","i-lucide-shuffle",{"title":83,"path":84,"stem":85,"icon":86},"安卓代码加固（6）：密钥外置","\u002Fandroid\u002Fhidden-hardening\u002Fkey-external","3.android\u002F02.hidden-hardening\u002F06.key-external","i-lucide-key",{"title":88,"path":89,"stem":90,"icon":91},"安卓代码加固（7）：依赖隔离","\u002Fandroid\u002Fhidden-hardening\u002Fdep-isolate","3.android\u002F02.hidden-hardening\u002F07.dep-isolate","i-lucide-layers",{"title":93,"path":94,"stem":95,"icon":96},"安卓代码加固（8）：构建校验","\u002Fandroid\u002Fhidden-hardening\u002Fbuild-verify","3.android\u002F02.hidden-hardening\u002F08.build-verify","i-lucide-shield-check",{"title":98,"path":99,"stem":100,"icon":101},"安卓代码加固（9）：防录屏","\u002Fandroid\u002Fhidden-hardening\u002Fflag-secure","3.android\u002F02.hidden-hardening\u002F09.flag-secure","i-lucide-eye-off",{"title":103,"path":104,"stem":105,"icon":106},"安卓代码加固（10）：ABI门禁","\u002Fandroid\u002Fhidden-hardening\u002Fabi-gate","3.android\u002F02.hidden-hardening\u002F10.abi-gate","i-lucide-git-compare",{"title":108,"icon":109,"path":110,"stem":111,"children":112},"iOS","i-simple-icons-apple","\u002Fios","4.ios",[113,115,120,125,129,133],{"title":108,"path":110,"stem":114,"icon":109},"4.ios\u002Findex",{"title":116,"path":117,"stem":118,"icon":119},"iOS面试题1","\u002Fios\u002Fios-interview1","4.ios\u002F01.ios-interview1","i-lucide-sparkles",{"title":121,"path":122,"stem":123,"icon":124},"设置启动图","\u002Fios\u002Fset-launch-screen","4.ios\u002F02.set-launch-screen","i-lucide-image",{"title":126,"path":127,"stem":128,"icon":48},"路由管理","\u002Fios\u002Frouting","4.ios\u002F03.routing",{"title":130,"path":131,"stem":132,"icon":91},"状态管理","\u002Fios\u002Fstate-management","4.ios\u002F04.state-management",{"title":134,"path":135,"stem":136,"icon":137},"事件传递","\u002Fios\u002Fevent-delivery","4.ios\u002F05.event-delivery","i-lucide-pointer",{"title":139,"path":140,"stem":141,"children":142,"icon":144},"Flutter","\u002Fflutter","5.flutter\u002Findex",[143],{"title":139,"path":140,"stem":141,"icon":144},"i-simple-icons-flutter",{"title":146,"icon":147,"path":148,"stem":149,"children":150,"page":160},"面试","i-lucide-graduation-cap","\u002Finterview","6.interview",[151,156],{"title":152,"path":153,"stem":154,"icon":155},"Flutter面试题1","\u002Finterview\u002Fflutter-interview1","6.interview\u002F01.flutter-interview1","i-lucide-boxes",{"title":157,"path":158,"stem":159,"icon":66},"Flutter面试题2","\u002Finterview\u002Fflutter-interview2","6.interview\u002F02.flutter-interview2",false,{"title":162,"icon":163,"path":164,"stem":165,"children":166},"算法学习","i-lucide-binary","\u002Falgorithm","7.algorithm",[167,169],{"title":162,"path":164,"stem":168,"icon":163},"7.algorithm\u002Findex",{"title":170,"path":171,"stem":172},"算法基础1：复杂度分析","\u002Falgorithm\u002Ftime-space-complexity","7.algorithm\u002F01.time-space-complexity",{"id":174,"title":126,"body":175,"description":4355,"extension":4356,"links":4357,"meta":4366,"navigation":4372,"path":127,"seo":4373,"stem":128,"__hash__":4376},"docs\u002F4.ios\u002F03.routing.md",{"type":176,"value":177,"toc":4334},"minimark",[178,195,215,218,222,345,353,356,369,385,388,391,718,744,747,762,1604,1607,1718,1724,1727,2117,2125,2128,2131,2380,2385,2388,2398,2401,2442,2445,2454,2462,2465,2476,2759,2762,3045,3057,3060,3069,3403,3421,3427,3620,3632,3641,3644,3653,4120,4126,4129,4140,4143,4165,4168,4171,4280,4289,4292,4295,4321,4330],[179,180,181,182,186,187,190,191,194],"p",{},"页面一多，跳转就散落在各个控制器里：这里 ",[183,184,185],"code",{},"push","，那里 ",[183,188,189],{},"present","，返回数据和深层链接各写一套。我现在的习惯是把目的地收成枚举，跳转只经过一个 ",[183,192,193],{},"Router","。UIKit 和 SwiftUI 的栈模型不一样，所以分成两套记。",[179,196,197,198,202,203,206,207,210,211,214],{},"环境按 ",[199,200,201],"strong",{},"Xcode 16","、",[199,204,205],{},"iOS 17"," 来写。SwiftUI 这段用 ",[183,208,209],{},"NavigationStack"," 和 ",[183,212,213],{},"@Observable","，更早的系统对不上。",[179,216,217],{},"路由里只放能重建页面的轻量值，一般是 ID、枚举、短字符串。列表、图片、网络响应留在页面自己的数据层里取。",[219,220,221],"h2",{"id":221},"两边各管什么",[223,224,225,240],"table",{},[226,227,228],"thead",{},[229,230,231,234,237],"tr",{},[232,233],"th",{},[232,235,236],{},"UIKit",[232,238,239],{},"SwiftUI",[241,242,243,262,276,296,316,329],"tbody",{},[229,244,245,249,254],{},[246,247,248],"td",{},"栈",[246,250,251],{},[183,252,253],{},"UINavigationController.viewControllers",[246,255,256,258,259],{},[183,257,209],{}," 的 ",[183,260,261],{},"path",[229,263,264,267,270],{},[246,265,266],{},"目的地",[246,268,269],{},"控制器实例",[246,271,272,275],{},[183,273,274],{},"Hashable"," 值",[229,277,278,281,286],{},[246,279,280],{},"谁改栈",[246,282,283,285],{},[183,284,193],{}," 拿着导航控制器",[246,287,288,290,291,293,294],{},[183,289,193],{}," 改 ",[183,292,261],{},"，栈手势也会写回 ",[183,295,261],{},[229,297,298,301,306],{},[246,299,300],{},"弹层",[246,302,303,305],{},[183,304,189],{},"，单独一条栈",[246,307,308,311,312,315],{},[183,309,310],{},"sheet"," \u002F ",[183,313,314],{},"fullScreenCover","，单独一个状态",[229,317,318,321,324],{},[246,319,320],{},"Tab",[246,322,323],{},"每个 Tab 一个导航控制器",[246,325,326,327],{},"每个 Tab 一个 ",[183,328,209],{},[229,330,331,334,339],{},[246,332,333],{},"深层链接入口",[246,335,336],{},[183,337,338],{},"SceneDelegate",[246,340,341,342],{},"根视图上的 ",[183,343,344],{},"onOpenURL",[179,346,347,348,210,350,352],{},"根页面留在栈底。",[183,349,261],{},[183,351,185],{}," 上去的都是根页面之上的那些页。",[219,354,236],{"id":355},"uikit",[179,357,358,359,361,362,365,366,368],{},"纯代码工程里，窗口和根控制器挂在 ",[183,360,338],{},"。起步步骤在 ",[363,364,13],"a",{"href":14},"。这里把根控制器换成导航控制器，再把导航控制器交给 ",[183,367,193],{},"。",[179,370,371,374,375,377,378,381,382,384],{},[183,372,373],{},"UINavigationController"," 负责压栈返回，",[183,376,189],{}," 负责弹层，",[183,379,380],{},"UITabBarController"," 负责 Tab。三件事分开，一个 ",[183,383,193],{}," 对外收口。",[386,387,266],"h3",{"id":266},[179,389,390],{},"根页面是首页，不放进枚举。枚举只描述「压到首页上面」或「弹出来」的页面。",[392,393,399],"pre",{"className":394,"code":395,"filename":396,"language":397,"meta":398,"style":398},"language-swift shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import Foundation\n\nenum AppRoute {\n    case profile(userId: String)\n    case settings\n}\n\nextension AppRoute {\n    \u002F\u002F\u002F myapp:\u002F\u002Fprofile\u002F42 、myapp:\u002F\u002Fsettings\n    init?(url: URL) {\n        guard url.scheme == \"myapp\" else { return nil }\n        switch url.host {\n        case \"profile\":\n            guard let userId = url.pathComponents.dropFirst().first, !userId.isEmpty else {\n                return nil\n            }\n            self = .profile(userId: userId)\n        case \"settings\":\n            self = .settings\n        default:\n            return nil\n        }\n    }\n}\n","AppRoute.swift","swift","",[183,400,401,414,421,435,461,469,475,480,490,497,517,554,566,582,622,631,637,661,675,685,693,701,707,713],{"__ignoreMap":398},[402,403,406,410],"span",{"class":404,"line":405},"line",1,[402,407,409],{"class":408},"s7zQu","import",[402,411,413],{"class":412},"sBMFI"," Foundation\n",[402,415,417],{"class":404,"line":416},2,[402,418,420],{"emptyLinePlaceholder":419},true,"\n",[402,422,424,428,431],{"class":404,"line":423},3,[402,425,427],{"class":426},"spNyl","enum",[402,429,430],{"class":412}," AppRoute",[402,432,434],{"class":433},"sMK4o"," {\n",[402,436,438,441,445,448,452,455,458],{"class":404,"line":437},4,[402,439,440],{"class":426},"    case",[402,442,444],{"class":443},"sTEyZ"," profile",[402,446,447],{"class":433},"(",[402,449,451],{"class":450},"sHdIc","userId",[402,453,454],{"class":433},":",[402,456,457],{"class":412}," String",[402,459,460],{"class":433},")\n",[402,462,464,466],{"class":404,"line":463},5,[402,465,440],{"class":426},[402,467,468],{"class":443}," settings\n",[402,470,472],{"class":404,"line":471},6,[402,473,474],{"class":433},"}\n",[402,476,478],{"class":404,"line":477},7,[402,479,420],{"emptyLinePlaceholder":419},[402,481,483,486,488],{"class":404,"line":482},8,[402,484,485],{"class":426},"extension",[402,487,430],{"class":412},[402,489,434],{"class":433},[402,491,493],{"class":404,"line":492},9,[402,494,496],{"class":495},"sHwdD","    \u002F\u002F\u002F myapp:\u002F\u002Fprofile\u002F42 、myapp:\u002F\u002Fsettings\n",[402,498,500,503,505,509,512,515],{"class":404,"line":499},10,[402,501,502],{"class":426},"    init?",[402,504,447],{"class":433},[402,506,508],{"class":507},"sjYur","url",[402,510,511],{"class":443},": URL",[402,513,514],{"class":433},")",[402,516,434],{"class":433},[402,518,520,523,526,529,532,536,539,542,545,548,551],{"class":404,"line":519},11,[402,521,522],{"class":408},"        guard",[402,524,525],{"class":443}," url.scheme ",[402,527,528],{"class":433},"==",[402,530,531],{"class":433}," \"",[402,533,535],{"class":534},"sfazB","myapp",[402,537,538],{"class":433},"\"",[402,540,541],{"class":408}," else",[402,543,544],{"class":433}," {",[402,546,547],{"class":408}," return",[402,549,550],{"class":433}," nil",[402,552,553],{"class":433}," }\n",[402,555,557,560,563],{"class":404,"line":556},12,[402,558,559],{"class":408},"        switch",[402,561,562],{"class":443}," url.host ",[402,564,565],{"class":433},"{\n",[402,567,569,572,574,577,579],{"class":404,"line":568},13,[402,570,571],{"class":408},"        case",[402,573,531],{"class":433},[402,575,576],{"class":534},"profile",[402,578,538],{"class":433},[402,580,581],{"class":433},":\n",[402,583,585,588,592,595,598,601,605,608,611,614,617,620],{"class":404,"line":584},14,[402,586,587],{"class":408},"            guard",[402,589,591],{"class":590},"sbssI"," let",[402,593,594],{"class":443}," userId ",[402,596,597],{"class":433},"=",[402,599,600],{"class":443}," url.pathComponents.",[402,602,604],{"class":603},"s2Zo4","dropFirst",[402,606,607],{"class":433},"()",[402,609,610],{"class":443},".first, ",[402,612,613],{"class":433},"!",[402,615,616],{"class":443},"userId.isEmpty ",[402,618,619],{"class":408},"else",[402,621,434],{"class":433},[402,623,625,628],{"class":404,"line":624},15,[402,626,627],{"class":408},"                return",[402,629,630],{"class":433}," nil\n",[402,632,634],{"class":404,"line":633},16,[402,635,636],{"class":433},"            }\n",[402,638,640,643,645,648,650,652,654,656,659],{"class":404,"line":639},17,[402,641,642],{"class":443},"            self ",[402,644,597],{"class":433},[402,646,647],{"class":443}," .",[402,649,576],{"class":603},[402,651,447],{"class":433},[402,653,451],{"class":603},[402,655,454],{"class":433},[402,657,658],{"class":443}," userId",[402,660,460],{"class":433},[402,662,664,666,668,671,673],{"class":404,"line":663},18,[402,665,571],{"class":408},[402,667,531],{"class":433},[402,669,670],{"class":534},"settings",[402,672,538],{"class":433},[402,674,581],{"class":433},[402,676,678,680,682],{"class":404,"line":677},19,[402,679,642],{"class":443},[402,681,597],{"class":433},[402,683,684],{"class":443}," .settings\n",[402,686,688,691],{"class":404,"line":687},20,[402,689,690],{"class":408},"        default",[402,692,581],{"class":433},[402,694,696,699],{"class":404,"line":695},21,[402,697,698],{"class":408},"            return",[402,700,630],{"class":433},[402,702,704],{"class":404,"line":703},22,[402,705,706],{"class":433},"        }\n",[402,708,710],{"class":404,"line":709},23,[402,711,712],{"class":433},"    }\n",[402,714,716],{"class":404,"line":715},24,[402,717,474],{"class":433},[179,719,720,721,724,725,728,729,732,733,736,737,740,741,368],{},"自定义 scheme 要在 target 的 ",[199,722,723],{},"Info"," → ",[199,726,727],{},"URL Types"," 里登记，对应 ",[183,730,731],{},"CFBundleURLTypes","。通用链接走的是 ",[183,734,735],{},"NSUserActivity","，解析放在 ",[183,738,739],{},"scene(_:continue:)","，解析完同样得到一个 ",[183,742,743],{},"AppRoute",[386,745,193],{"id":746},"router",[179,748,749,750,752,753,755,756,758,759,761],{},"控制器只通过弱引用调用 ",[183,751,193],{},"，自己不 ",[183,754,185],{}," 别的控制器。",[183,757,193],{}," 由 ",[183,760,338],{}," 持有，导航控制器由窗口持有。",[392,763,766],{"className":394,"code":764,"filename":765,"language":397,"meta":398,"style":398},"import UIKit\n\nfinal class AppRouter {\n    private let navigationController: UINavigationController\n\n    init(navigationController: UINavigationController) {\n        self.navigationController = navigationController\n    }\n\n    func start() {\n        navigationController.setViewControllers([makeHome()], animated: false)\n    }\n\n    func push(_ route: AppRoute) {\n        navigationController.pushViewController(makeViewController(for: route), animated: true)\n    }\n\n    func pop() {\n        navigationController.popViewController(animated: true)\n    }\n\n    func popToRoot() {\n        navigationController.popToRootViewController(animated: true)\n    }\n\n    func present(_ route: AppRoute) {\n        let sheet = UINavigationController(rootViewController: makeViewController(for: route))\n        sheet.modalPresentationStyle = .pageSheet\n        navigationController.present(sheet, animated: true)\n    }\n\n    func dismiss() {\n        navigationController.dismiss(animated: true)\n    }\n\n    \u002F\u002F\u002F 冷启动用 resetStack，保证栈是 [首页, 目标页]，返回能回到首页。\n    func open(url: URL, resetStack: Bool) {\n        guard let route = AppRoute(url: url) else { return }\n        let target = makeViewController(for: route)\n        if resetStack {\n            navigationController.setViewControllers([makeHome(), target], animated: false)\n        } else {\n            navigationController.pushViewController(target, animated: true)\n        }\n    }\n\n    private func makeHome() -> UIViewController {\n        let viewController = HomeViewController()\n        viewController.router = self\n        return viewController\n    }\n\n    private func makeViewController(for route: AppRoute) -> UIViewController {\n        let viewController: UIViewController\n        switch route {\n        case .profile(let userId):\n            viewController = ProfileViewController(userId: userId)\n        case .settings:\n            viewController = SettingsViewController()\n        }\n        (viewController as? Routable)?.router = self\n        return viewController\n    }\n}\n\nprotocol Routable: AnyObject {\n    var router: AppRouter? { get set }\n}\n","AppRouter.swift",[183,767,768,775,779,792,802,806,823,833,837,841,853,885,889,893,915,950,954,958,969,986,990,994,1005,1022,1026,1031,1051,1086,1097,1117,1122,1127,1139,1157,1162,1167,1173,1201,1234,1256,1267,1294,1304,1324,1329,1334,1339,1360,1376,1387,1396,1401,1406,1431,1439,1448,1467,1488,1498,1510,1515,1540,1547,1552,1557,1562,1577,1599],{"__ignoreMap":398},[402,769,770,772],{"class":404,"line":405},[402,771,409],{"class":408},[402,773,774],{"class":412}," UIKit\n",[402,776,777],{"class":404,"line":416},[402,778,420],{"emptyLinePlaceholder":419},[402,780,781,784,787,790],{"class":404,"line":423},[402,782,783],{"class":426},"final",[402,785,786],{"class":426}," class",[402,788,789],{"class":412}," AppRouter",[402,791,434],{"class":433},[402,793,794,797,799],{"class":404,"line":437},[402,795,796],{"class":590},"    private",[402,798,591],{"class":590},[402,800,801],{"class":443}," navigationController: UINavigationController\n",[402,803,804],{"class":404,"line":463},[402,805,420],{"emptyLinePlaceholder":419},[402,807,808,811,813,816,819,821],{"class":404,"line":471},[402,809,810],{"class":426},"    init",[402,812,447],{"class":433},[402,814,815],{"class":507},"navigationController",[402,817,818],{"class":443},": UINavigationController",[402,820,514],{"class":433},[402,822,434],{"class":433},[402,824,825,828,830],{"class":404,"line":477},[402,826,827],{"class":443},"        self.navigationController ",[402,829,597],{"class":433},[402,831,832],{"class":443}," navigationController\n",[402,834,835],{"class":404,"line":482},[402,836,712],{"class":433},[402,838,839],{"class":404,"line":492},[402,840,420],{"emptyLinePlaceholder":419},[402,842,843,846,849,851],{"class":404,"line":499},[402,844,845],{"class":426},"    func",[402,847,848],{"class":603}," start",[402,850,607],{"class":433},[402,852,434],{"class":433},[402,854,855,858,861,863,866,869,871,874,877,879,883],{"class":404,"line":519},[402,856,857],{"class":443},"        navigationController.",[402,859,860],{"class":603},"setViewControllers",[402,862,447],{"class":433},[402,864,865],{"class":443},"[",[402,867,868],{"class":603},"makeHome",[402,870,607],{"class":433},[402,872,873],{"class":443},"], ",[402,875,876],{"class":603},"animated",[402,878,454],{"class":433},[402,880,882],{"class":881},"sfNiH"," false",[402,884,460],{"class":433},[402,886,887],{"class":404,"line":556},[402,888,712],{"class":433},[402,890,891],{"class":404,"line":568},[402,892,420],{"emptyLinePlaceholder":419},[402,894,895,897,900,902,905,908,911,913],{"class":404,"line":584},[402,896,845],{"class":426},[402,898,899],{"class":603}," push",[402,901,447],{"class":433},[402,903,904],{"class":603},"_",[402,906,907],{"class":450}," route",[402,909,910],{"class":443},": AppRoute",[402,912,514],{"class":433},[402,914,434],{"class":433},[402,916,917,919,922,924,927,929,932,934,936,938,941,943,945,948],{"class":404,"line":624},[402,918,857],{"class":443},[402,920,921],{"class":603},"pushViewController",[402,923,447],{"class":433},[402,925,926],{"class":603},"makeViewController",[402,928,447],{"class":433},[402,930,931],{"class":603},"for",[402,933,454],{"class":433},[402,935,907],{"class":443},[402,937,514],{"class":433},[402,939,940],{"class":443},", ",[402,942,876],{"class":603},[402,944,454],{"class":433},[402,946,947],{"class":881}," true",[402,949,460],{"class":433},[402,951,952],{"class":404,"line":633},[402,953,712],{"class":433},[402,955,956],{"class":404,"line":639},[402,957,420],{"emptyLinePlaceholder":419},[402,959,960,962,965,967],{"class":404,"line":663},[402,961,845],{"class":426},[402,963,964],{"class":603}," pop",[402,966,607],{"class":433},[402,968,434],{"class":433},[402,970,971,973,976,978,980,982,984],{"class":404,"line":677},[402,972,857],{"class":443},[402,974,975],{"class":603},"popViewController",[402,977,447],{"class":433},[402,979,876],{"class":603},[402,981,454],{"class":433},[402,983,947],{"class":881},[402,985,460],{"class":433},[402,987,988],{"class":404,"line":687},[402,989,712],{"class":433},[402,991,992],{"class":404,"line":695},[402,993,420],{"emptyLinePlaceholder":419},[402,995,996,998,1001,1003],{"class":404,"line":703},[402,997,845],{"class":426},[402,999,1000],{"class":603}," popToRoot",[402,1002,607],{"class":433},[402,1004,434],{"class":433},[402,1006,1007,1009,1012,1014,1016,1018,1020],{"class":404,"line":709},[402,1008,857],{"class":443},[402,1010,1011],{"class":603},"popToRootViewController",[402,1013,447],{"class":433},[402,1015,876],{"class":603},[402,1017,454],{"class":433},[402,1019,947],{"class":881},[402,1021,460],{"class":433},[402,1023,1024],{"class":404,"line":715},[402,1025,712],{"class":433},[402,1027,1029],{"class":404,"line":1028},25,[402,1030,420],{"emptyLinePlaceholder":419},[402,1032,1034,1036,1039,1041,1043,1045,1047,1049],{"class":404,"line":1033},26,[402,1035,845],{"class":426},[402,1037,1038],{"class":603}," present",[402,1040,447],{"class":433},[402,1042,904],{"class":603},[402,1044,907],{"class":450},[402,1046,910],{"class":443},[402,1048,514],{"class":433},[402,1050,434],{"class":433},[402,1052,1054,1057,1060,1062,1065,1067,1070,1072,1075,1077,1079,1081,1083],{"class":404,"line":1053},27,[402,1055,1056],{"class":590},"        let",[402,1058,1059],{"class":443}," sheet ",[402,1061,597],{"class":433},[402,1063,1064],{"class":603}," UINavigationController",[402,1066,447],{"class":433},[402,1068,1069],{"class":603},"rootViewController",[402,1071,454],{"class":433},[402,1073,1074],{"class":603}," makeViewController",[402,1076,447],{"class":433},[402,1078,931],{"class":603},[402,1080,454],{"class":433},[402,1082,907],{"class":443},[402,1084,1085],{"class":433},"))\n",[402,1087,1089,1092,1094],{"class":404,"line":1088},28,[402,1090,1091],{"class":443},"        sheet.modalPresentationStyle ",[402,1093,597],{"class":433},[402,1095,1096],{"class":443}," .pageSheet\n",[402,1098,1100,1102,1104,1106,1109,1111,1113,1115],{"class":404,"line":1099},29,[402,1101,857],{"class":443},[402,1103,189],{"class":603},[402,1105,447],{"class":433},[402,1107,1108],{"class":443},"sheet, ",[402,1110,876],{"class":603},[402,1112,454],{"class":433},[402,1114,947],{"class":881},[402,1116,460],{"class":433},[402,1118,1120],{"class":404,"line":1119},30,[402,1121,712],{"class":433},[402,1123,1125],{"class":404,"line":1124},31,[402,1126,420],{"emptyLinePlaceholder":419},[402,1128,1130,1132,1135,1137],{"class":404,"line":1129},32,[402,1131,845],{"class":426},[402,1133,1134],{"class":603}," dismiss",[402,1136,607],{"class":433},[402,1138,434],{"class":433},[402,1140,1142,1144,1147,1149,1151,1153,1155],{"class":404,"line":1141},33,[402,1143,857],{"class":443},[402,1145,1146],{"class":603},"dismiss",[402,1148,447],{"class":433},[402,1150,876],{"class":603},[402,1152,454],{"class":433},[402,1154,947],{"class":881},[402,1156,460],{"class":433},[402,1158,1160],{"class":404,"line":1159},34,[402,1161,712],{"class":433},[402,1163,1165],{"class":404,"line":1164},35,[402,1166,420],{"emptyLinePlaceholder":419},[402,1168,1170],{"class":404,"line":1169},36,[402,1171,1172],{"class":495},"    \u002F\u002F\u002F 冷启动用 resetStack，保证栈是 [首页, 目标页]，返回能回到首页。\n",[402,1174,1176,1178,1181,1183,1185,1188,1191,1194,1197,1199],{"class":404,"line":1175},37,[402,1177,845],{"class":426},[402,1179,1180],{"class":603}," open",[402,1182,447],{"class":433},[402,1184,508],{"class":507},[402,1186,1187],{"class":443},": URL, ",[402,1189,1190],{"class":507},"resetStack",[402,1192,1193],{"class":443},": ",[402,1195,1196],{"class":412},"Bool",[402,1198,514],{"class":433},[402,1200,434],{"class":433},[402,1202,1204,1206,1208,1211,1213,1215,1217,1219,1221,1224,1226,1228,1230,1232],{"class":404,"line":1203},38,[402,1205,522],{"class":408},[402,1207,591],{"class":590},[402,1209,1210],{"class":443}," route ",[402,1212,597],{"class":433},[402,1214,430],{"class":603},[402,1216,447],{"class":433},[402,1218,508],{"class":603},[402,1220,454],{"class":433},[402,1222,1223],{"class":443}," url",[402,1225,514],{"class":433},[402,1227,541],{"class":408},[402,1229,544],{"class":433},[402,1231,547],{"class":408},[402,1233,553],{"class":433},[402,1235,1237,1239,1242,1244,1246,1248,1250,1252,1254],{"class":404,"line":1236},39,[402,1238,1056],{"class":590},[402,1240,1241],{"class":443}," target ",[402,1243,597],{"class":433},[402,1245,1074],{"class":603},[402,1247,447],{"class":433},[402,1249,931],{"class":603},[402,1251,454],{"class":433},[402,1253,907],{"class":443},[402,1255,460],{"class":433},[402,1257,1259,1262,1265],{"class":404,"line":1258},40,[402,1260,1261],{"class":408},"        if",[402,1263,1264],{"class":443}," resetStack ",[402,1266,565],{"class":433},[402,1268,1270,1273,1275,1277,1279,1281,1283,1286,1288,1290,1292],{"class":404,"line":1269},41,[402,1271,1272],{"class":443},"            navigationController.",[402,1274,860],{"class":603},[402,1276,447],{"class":433},[402,1278,865],{"class":443},[402,1280,868],{"class":603},[402,1282,607],{"class":433},[402,1284,1285],{"class":443},", target], ",[402,1287,876],{"class":603},[402,1289,454],{"class":433},[402,1291,882],{"class":881},[402,1293,460],{"class":433},[402,1295,1297,1300,1302],{"class":404,"line":1296},42,[402,1298,1299],{"class":433},"        }",[402,1301,541],{"class":408},[402,1303,434],{"class":433},[402,1305,1307,1309,1311,1313,1316,1318,1320,1322],{"class":404,"line":1306},43,[402,1308,1272],{"class":443},[402,1310,921],{"class":603},[402,1312,447],{"class":433},[402,1314,1315],{"class":443},"target, ",[402,1317,876],{"class":603},[402,1319,454],{"class":433},[402,1321,947],{"class":881},[402,1323,460],{"class":433},[402,1325,1327],{"class":404,"line":1326},44,[402,1328,706],{"class":433},[402,1330,1332],{"class":404,"line":1331},45,[402,1333,712],{"class":433},[402,1335,1337],{"class":404,"line":1336},46,[402,1338,420],{"emptyLinePlaceholder":419},[402,1340,1342,1344,1347,1350,1352,1355,1358],{"class":404,"line":1341},47,[402,1343,796],{"class":590},[402,1345,1346],{"class":426}," func",[402,1348,1349],{"class":603}," makeHome",[402,1351,607],{"class":433},[402,1353,1354],{"class":433}," ->",[402,1356,1357],{"class":443}," UIViewController ",[402,1359,565],{"class":433},[402,1361,1363,1365,1368,1370,1373],{"class":404,"line":1362},48,[402,1364,1056],{"class":590},[402,1366,1367],{"class":443}," viewController ",[402,1369,597],{"class":433},[402,1371,1372],{"class":603}," HomeViewController",[402,1374,1375],{"class":433},"()\n",[402,1377,1379,1382,1384],{"class":404,"line":1378},49,[402,1380,1381],{"class":443},"        viewController.router ",[402,1383,597],{"class":433},[402,1385,1386],{"class":443}," self\n",[402,1388,1390,1393],{"class":404,"line":1389},50,[402,1391,1392],{"class":408},"        return",[402,1394,1395],{"class":443}," viewController\n",[402,1397,1399],{"class":404,"line":1398},51,[402,1400,712],{"class":433},[402,1402,1404],{"class":404,"line":1403},52,[402,1405,420],{"emptyLinePlaceholder":419},[402,1407,1409,1411,1413,1415,1417,1419,1421,1423,1425,1427,1429],{"class":404,"line":1408},53,[402,1410,796],{"class":590},[402,1412,1346],{"class":426},[402,1414,1074],{"class":603},[402,1416,447],{"class":433},[402,1418,931],{"class":603},[402,1420,907],{"class":450},[402,1422,910],{"class":443},[402,1424,514],{"class":433},[402,1426,1354],{"class":433},[402,1428,1357],{"class":443},[402,1430,565],{"class":433},[402,1432,1434,1436],{"class":404,"line":1433},54,[402,1435,1056],{"class":590},[402,1437,1438],{"class":443}," viewController: UIViewController\n",[402,1440,1442,1444,1446],{"class":404,"line":1441},55,[402,1443,559],{"class":408},[402,1445,1210],{"class":443},[402,1447,565],{"class":433},[402,1449,1451,1453,1455,1457,1459,1462,1464],{"class":404,"line":1450},56,[402,1452,571],{"class":408},[402,1454,647],{"class":443},[402,1456,576],{"class":603},[402,1458,447],{"class":433},[402,1460,1461],{"class":590},"let",[402,1463,658],{"class":443},[402,1465,1466],{"class":433},"):\n",[402,1468,1470,1473,1475,1478,1480,1482,1484,1486],{"class":404,"line":1469},57,[402,1471,1472],{"class":443},"            viewController ",[402,1474,597],{"class":433},[402,1476,1477],{"class":603}," ProfileViewController",[402,1479,447],{"class":433},[402,1481,451],{"class":603},[402,1483,454],{"class":433},[402,1485,658],{"class":443},[402,1487,460],{"class":433},[402,1489,1491,1493,1496],{"class":404,"line":1490},58,[402,1492,571],{"class":408},[402,1494,1495],{"class":443}," .settings",[402,1497,581],{"class":433},[402,1499,1501,1503,1505,1508],{"class":404,"line":1500},59,[402,1502,1472],{"class":443},[402,1504,597],{"class":433},[402,1506,1507],{"class":603}," SettingsViewController",[402,1509,1375],{"class":433},[402,1511,1513],{"class":404,"line":1512},60,[402,1514,706],{"class":433},[402,1516,1518,1521,1524,1527,1530,1533,1536,1538],{"class":404,"line":1517},61,[402,1519,1520],{"class":433},"        (",[402,1522,1523],{"class":443},"viewController ",[402,1525,1526],{"class":433},"as?",[402,1528,1529],{"class":443}," Routable",[402,1531,1532],{"class":433},")?",[402,1534,1535],{"class":443},".router ",[402,1537,597],{"class":433},[402,1539,1386],{"class":443},[402,1541,1543,1545],{"class":404,"line":1542},62,[402,1544,1392],{"class":408},[402,1546,1395],{"class":443},[402,1548,1550],{"class":404,"line":1549},63,[402,1551,712],{"class":433},[402,1553,1555],{"class":404,"line":1554},64,[402,1556,474],{"class":433},[402,1558,1560],{"class":404,"line":1559},65,[402,1561,420],{"emptyLinePlaceholder":419},[402,1563,1565,1568,1570,1572,1575],{"class":404,"line":1564},66,[402,1566,1567],{"class":426},"protocol",[402,1569,1529],{"class":412},[402,1571,454],{"class":433},[402,1573,1574],{"class":412}," AnyObject ",[402,1576,565],{"class":433},[402,1578,1580,1583,1586,1589,1591,1594,1597],{"class":404,"line":1579},67,[402,1581,1582],{"class":590},"    var",[402,1584,1585],{"class":443}," router: AppRouter",[402,1587,1588],{"class":433},"?",[402,1590,544],{"class":433},[402,1592,1593],{"class":426}," get",[402,1595,1596],{"class":426}," set",[402,1598,553],{"class":433},[402,1600,1602],{"class":404,"line":1601},68,[402,1603,474],{"class":433},[179,1605,1606],{},"页面侧只留入口：",[392,1608,1611],{"className":394,"code":1609,"filename":1610,"language":397,"meta":398,"style":398},"import UIKit\n\nfinal class HomeViewController: UIViewController, Routable {\n    weak var router: AppRouter?\n\n    private func openProfile(userId: String) {\n        router?.push(.profile(userId: userId))\n    }\n}\n","HomeViewController.swift",[183,1612,1613,1619,1623,1643,1656,1660,1682,1710,1714],{"__ignoreMap":398},[402,1614,1615,1617],{"class":404,"line":405},[402,1616,409],{"class":408},[402,1618,774],{"class":412},[402,1620,1621],{"class":404,"line":416},[402,1622,420],{"emptyLinePlaceholder":419},[402,1624,1625,1627,1629,1631,1633,1636,1638,1641],{"class":404,"line":423},[402,1626,783],{"class":426},[402,1628,786],{"class":426},[402,1630,1372],{"class":412},[402,1632,454],{"class":433},[402,1634,1635],{"class":412}," UIViewController",[402,1637,940],{"class":443},[402,1639,1640],{"class":412},"Routable ",[402,1642,565],{"class":433},[402,1644,1645,1648,1651,1653],{"class":404,"line":437},[402,1646,1647],{"class":590},"    weak",[402,1649,1650],{"class":590}," var",[402,1652,1585],{"class":443},[402,1654,1655],{"class":433},"?\n",[402,1657,1658],{"class":404,"line":463},[402,1659,420],{"emptyLinePlaceholder":419},[402,1661,1662,1664,1666,1669,1671,1673,1675,1678,1680],{"class":404,"line":471},[402,1663,796],{"class":590},[402,1665,1346],{"class":426},[402,1667,1668],{"class":603}," openProfile",[402,1670,447],{"class":433},[402,1672,451],{"class":507},[402,1674,1193],{"class":443},[402,1676,1677],{"class":412},"String",[402,1679,514],{"class":433},[402,1681,434],{"class":433},[402,1683,1684,1687,1689,1692,1694,1696,1698,1700,1702,1704,1706,1708],{"class":404,"line":477},[402,1685,1686],{"class":443},"        router",[402,1688,1588],{"class":433},[402,1690,1691],{"class":443},".",[402,1693,185],{"class":603},[402,1695,447],{"class":433},[402,1697,1691],{"class":443},[402,1699,576],{"class":603},[402,1701,447],{"class":433},[402,1703,451],{"class":603},[402,1705,454],{"class":433},[402,1707,658],{"class":443},[402,1709,1085],{"class":433},[402,1711,1712],{"class":404,"line":482},[402,1713,712],{"class":433},[402,1715,1716],{"class":404,"line":492},[402,1717,474],{"class":433},[179,1719,1720,1721,1723],{},"这套写法常见的名字是 Coordinator。这里收成一个 ",[183,1722,193],{},"，是为了和后面的 SwiftUI 对照。模块变多时，可以按 Tab 或业务流程再拆几个子 Router，每个子 Router 拿自己的导航控制器。",[386,1725,1726],{"id":1726},"挂到窗口上",[392,1728,1731],{"className":394,"code":1729,"filename":1730,"language":397,"meta":398,"style":398},"import UIKit\n\nclass SceneDelegate: UIResponder, UIWindowSceneDelegate {\n    var window: UIWindow?\n    private var router: AppRouter?\n\n    func scene(\n        _ scene: UIScene,\n        willConnectTo session: UISceneSession,\n        options connectionOptions: UIScene.ConnectionOptions\n    ) {\n        guard let windowScene = scene as? UIWindowScene else { return }\n        let navigationController = UINavigationController()\n        let router = AppRouter(navigationController: navigationController)\n        router.start()\n        if let url = connectionOptions.urlContexts.first?.url {\n            router.open(url: url, resetStack: true)\n        }\n        window = UIWindow(windowScene: windowScene)\n        window?.rootViewController = navigationController\n        window?.makeKeyAndVisible()\n        self.router = router\n    }\n\n    func scene(_ scene: UIScene, openURLContexts URLContexts: Set\u003CUIOpenURLContext>) {\n        guard let url = URLContexts.first?.url else { return }\n        router?.open(url: url, resetStack: false)\n    }\n}\n","SceneDelegate.swift",[183,1732,1733,1739,1743,1763,1772,1782,1786,1796,1806,1817,1828,1835,1862,1875,1897,1904,1925,1950,1954,1976,1990,2003,2013,2017,2021,2058,2083,2109,2113],{"__ignoreMap":398},[402,1734,1735,1737],{"class":404,"line":405},[402,1736,409],{"class":408},[402,1738,774],{"class":412},[402,1740,1741],{"class":404,"line":416},[402,1742,420],{"emptyLinePlaceholder":419},[402,1744,1745,1748,1751,1753,1756,1758,1761],{"class":404,"line":423},[402,1746,1747],{"class":426},"class",[402,1749,1750],{"class":412}," SceneDelegate",[402,1752,454],{"class":433},[402,1754,1755],{"class":412}," UIResponder",[402,1757,940],{"class":443},[402,1759,1760],{"class":412},"UIWindowSceneDelegate ",[402,1762,565],{"class":433},[402,1764,1765,1767,1770],{"class":404,"line":437},[402,1766,1582],{"class":590},[402,1768,1769],{"class":443}," window: UIWindow",[402,1771,1655],{"class":433},[402,1773,1774,1776,1778,1780],{"class":404,"line":463},[402,1775,796],{"class":590},[402,1777,1650],{"class":590},[402,1779,1585],{"class":443},[402,1781,1655],{"class":433},[402,1783,1784],{"class":404,"line":471},[402,1785,420],{"emptyLinePlaceholder":419},[402,1787,1788,1790,1793],{"class":404,"line":477},[402,1789,845],{"class":426},[402,1791,1792],{"class":603}," scene",[402,1794,1795],{"class":433},"(\n",[402,1797,1798,1801,1803],{"class":404,"line":482},[402,1799,1800],{"class":603},"        _",[402,1802,1792],{"class":450},[402,1804,1805],{"class":443},": UIScene,\n",[402,1807,1808,1811,1814],{"class":404,"line":492},[402,1809,1810],{"class":603},"        willConnectTo",[402,1812,1813],{"class":450}," session",[402,1815,1816],{"class":443},": UISceneSession,\n",[402,1818,1819,1822,1825],{"class":404,"line":499},[402,1820,1821],{"class":603},"        options",[402,1823,1824],{"class":450}," connectionOptions",[402,1826,1827],{"class":443},": UIScene.ConnectionOptions\n",[402,1829,1830,1833],{"class":404,"line":519},[402,1831,1832],{"class":433},"    )",[402,1834,434],{"class":433},[402,1836,1837,1839,1841,1844,1846,1849,1851,1854,1856,1858,1860],{"class":404,"line":556},[402,1838,522],{"class":408},[402,1840,591],{"class":590},[402,1842,1843],{"class":443}," windowScene ",[402,1845,597],{"class":433},[402,1847,1848],{"class":443}," scene ",[402,1850,1526],{"class":433},[402,1852,1853],{"class":443}," UIWindowScene ",[402,1855,619],{"class":408},[402,1857,544],{"class":433},[402,1859,547],{"class":408},[402,1861,553],{"class":433},[402,1863,1864,1866,1869,1871,1873],{"class":404,"line":568},[402,1865,1056],{"class":590},[402,1867,1868],{"class":443}," navigationController ",[402,1870,597],{"class":433},[402,1872,1064],{"class":603},[402,1874,1375],{"class":433},[402,1876,1877,1879,1882,1884,1886,1888,1890,1892,1895],{"class":404,"line":584},[402,1878,1056],{"class":590},[402,1880,1881],{"class":443}," router ",[402,1883,597],{"class":433},[402,1885,789],{"class":603},[402,1887,447],{"class":433},[402,1889,815],{"class":603},[402,1891,454],{"class":433},[402,1893,1894],{"class":443}," navigationController",[402,1896,460],{"class":433},[402,1898,1899,1902],{"class":404,"line":624},[402,1900,1901],{"class":443},"        router.start",[402,1903,1375],{"class":433},[402,1905,1906,1908,1910,1913,1915,1918,1920,1923],{"class":404,"line":633},[402,1907,1261],{"class":408},[402,1909,591],{"class":590},[402,1911,1912],{"class":443}," url ",[402,1914,597],{"class":433},[402,1916,1917],{"class":443}," connectionOptions.urlContexts.first",[402,1919,1588],{"class":433},[402,1921,1922],{"class":443},".url ",[402,1924,565],{"class":433},[402,1926,1927,1930,1933,1935,1937,1939,1942,1944,1946,1948],{"class":404,"line":639},[402,1928,1929],{"class":443},"            router.",[402,1931,1932],{"class":603},"open",[402,1934,447],{"class":433},[402,1936,508],{"class":603},[402,1938,454],{"class":433},[402,1940,1941],{"class":443}," url, ",[402,1943,1190],{"class":603},[402,1945,454],{"class":433},[402,1947,947],{"class":881},[402,1949,460],{"class":433},[402,1951,1952],{"class":404,"line":663},[402,1953,706],{"class":433},[402,1955,1956,1959,1961,1964,1966,1969,1971,1974],{"class":404,"line":677},[402,1957,1958],{"class":443},"        window ",[402,1960,597],{"class":433},[402,1962,1963],{"class":603}," UIWindow",[402,1965,447],{"class":433},[402,1967,1968],{"class":603},"windowScene",[402,1970,454],{"class":433},[402,1972,1973],{"class":443}," windowScene",[402,1975,460],{"class":433},[402,1977,1978,1981,1983,1986,1988],{"class":404,"line":687},[402,1979,1980],{"class":443},"        window",[402,1982,1588],{"class":433},[402,1984,1985],{"class":443},".rootViewController ",[402,1987,597],{"class":433},[402,1989,832],{"class":443},[402,1991,1992,1994,1996,1998,2001],{"class":404,"line":695},[402,1993,1980],{"class":443},[402,1995,1588],{"class":433},[402,1997,1691],{"class":443},[402,1999,2000],{"class":603},"makeKeyAndVisible",[402,2002,1375],{"class":433},[402,2004,2005,2008,2010],{"class":404,"line":703},[402,2006,2007],{"class":443},"        self.router ",[402,2009,597],{"class":433},[402,2011,2012],{"class":443}," router\n",[402,2014,2015],{"class":404,"line":709},[402,2016,712],{"class":433},[402,2018,2019],{"class":404,"line":715},[402,2020,420],{"emptyLinePlaceholder":419},[402,2022,2023,2025,2027,2029,2031,2033,2036,2039,2042,2044,2047,2050,2053,2056],{"class":404,"line":1028},[402,2024,845],{"class":426},[402,2026,1792],{"class":603},[402,2028,447],{"class":433},[402,2030,904],{"class":603},[402,2032,1792],{"class":450},[402,2034,2035],{"class":443},": UIScene, ",[402,2037,2038],{"class":603},"openURLContexts",[402,2040,2041],{"class":450}," URLContexts",[402,2043,1193],{"class":443},[402,2045,2046],{"class":412},"Set",[402,2048,2049],{"class":433},"\u003C",[402,2051,2052],{"class":443},"UIOpenURLContext",[402,2054,2055],{"class":433},">)",[402,2057,434],{"class":433},[402,2059,2060,2062,2064,2066,2068,2071,2073,2075,2077,2079,2081],{"class":404,"line":1033},[402,2061,522],{"class":408},[402,2063,591],{"class":590},[402,2065,1912],{"class":443},[402,2067,597],{"class":433},[402,2069,2070],{"class":443}," URLContexts.first",[402,2072,1588],{"class":433},[402,2074,1922],{"class":443},[402,2076,619],{"class":408},[402,2078,544],{"class":433},[402,2080,547],{"class":408},[402,2082,553],{"class":433},[402,2084,2085,2087,2089,2091,2093,2095,2097,2099,2101,2103,2105,2107],{"class":404,"line":1053},[402,2086,1686],{"class":443},[402,2088,1588],{"class":433},[402,2090,1691],{"class":443},[402,2092,1932],{"class":603},[402,2094,447],{"class":433},[402,2096,508],{"class":603},[402,2098,454],{"class":433},[402,2100,1941],{"class":443},[402,2102,1190],{"class":603},[402,2104,454],{"class":433},[402,2106,882],{"class":881},[402,2108,460],{"class":433},[402,2110,2111],{"class":404,"line":1088},[402,2112,712],{"class":433},[402,2114,2115],{"class":404,"line":1099},[402,2116,474],{"class":433},[179,2118,2119,2122,2123,368],{},[183,2120,2121],{},"willConnectTo"," 只在场景建立时进来，App 已经在前台时再点链接，走 ",[183,2124,2038],{},[386,2126,320],{"id":2127},"tab",[179,2129,2130],{},"每个 Tab 各自一条导航栈，返回和深层链接才不会串。",[392,2132,2134],{"className":394,"code":2133,"filename":1730,"language":397,"meta":398,"style":398},"let homeNav = UINavigationController()\nlet profileNav = UINavigationController()\nlet homeRouter = AppRouter(navigationController: homeNav)\nlet profileRouter = AppRouter(navigationController: profileNav)\nhomeRouter.start()\nprofileRouter.start()\n\nlet tabs = UITabBarController()\nhomeNav.tabBarItem = UITabBarItem(title: \"首页\", image: UIImage(systemName: \"house\"), tag: 0)\nprofileNav.tabBarItem = UITabBarItem(title: \"我的\", image: UIImage(systemName: \"person\"), tag: 1)\ntabs.viewControllers = [homeNav, profileNav]\nwindow?.rootViewController = tabs\n",[183,2135,2136,2149,2162,2184,2206,2213,2220,2224,2238,2300,2356,2366],{"__ignoreMap":398},[402,2137,2138,2140,2143,2145,2147],{"class":404,"line":405},[402,2139,1461],{"class":590},[402,2141,2142],{"class":443}," homeNav ",[402,2144,597],{"class":433},[402,2146,1064],{"class":603},[402,2148,1375],{"class":433},[402,2150,2151,2153,2156,2158,2160],{"class":404,"line":416},[402,2152,1461],{"class":590},[402,2154,2155],{"class":443}," profileNav ",[402,2157,597],{"class":433},[402,2159,1064],{"class":603},[402,2161,1375],{"class":433},[402,2163,2164,2166,2169,2171,2173,2175,2177,2179,2182],{"class":404,"line":423},[402,2165,1461],{"class":590},[402,2167,2168],{"class":443}," homeRouter ",[402,2170,597],{"class":433},[402,2172,789],{"class":603},[402,2174,447],{"class":433},[402,2176,815],{"class":603},[402,2178,454],{"class":433},[402,2180,2181],{"class":443}," homeNav",[402,2183,460],{"class":433},[402,2185,2186,2188,2191,2193,2195,2197,2199,2201,2204],{"class":404,"line":437},[402,2187,1461],{"class":590},[402,2189,2190],{"class":443}," profileRouter ",[402,2192,597],{"class":433},[402,2194,789],{"class":603},[402,2196,447],{"class":433},[402,2198,815],{"class":603},[402,2200,454],{"class":433},[402,2202,2203],{"class":443}," profileNav",[402,2205,460],{"class":433},[402,2207,2208,2211],{"class":404,"line":463},[402,2209,2210],{"class":443},"homeRouter.start",[402,2212,1375],{"class":433},[402,2214,2215,2218],{"class":404,"line":471},[402,2216,2217],{"class":443},"profileRouter.start",[402,2219,1375],{"class":433},[402,2221,2222],{"class":404,"line":477},[402,2223,420],{"emptyLinePlaceholder":419},[402,2225,2226,2228,2231,2233,2236],{"class":404,"line":482},[402,2227,1461],{"class":590},[402,2229,2230],{"class":443}," tabs ",[402,2232,597],{"class":433},[402,2234,2235],{"class":603}," UITabBarController",[402,2237,1375],{"class":433},[402,2239,2240,2243,2245,2248,2250,2253,2255,2257,2260,2262,2264,2267,2269,2272,2274,2277,2279,2281,2284,2286,2288,2290,2293,2295,2298],{"class":404,"line":492},[402,2241,2242],{"class":443},"homeNav.tabBarItem ",[402,2244,597],{"class":433},[402,2246,2247],{"class":603}," UITabBarItem",[402,2249,447],{"class":433},[402,2251,2252],{"class":603},"title",[402,2254,454],{"class":433},[402,2256,531],{"class":433},[402,2258,2259],{"class":534},"首页",[402,2261,538],{"class":433},[402,2263,940],{"class":443},[402,2265,2266],{"class":603},"image",[402,2268,454],{"class":433},[402,2270,2271],{"class":603}," UIImage",[402,2273,447],{"class":433},[402,2275,2276],{"class":603},"systemName",[402,2278,454],{"class":433},[402,2280,531],{"class":433},[402,2282,2283],{"class":534},"house",[402,2285,538],{"class":433},[402,2287,514],{"class":433},[402,2289,940],{"class":443},[402,2291,2292],{"class":603},"tag",[402,2294,454],{"class":433},[402,2296,2297],{"class":590}," 0",[402,2299,460],{"class":433},[402,2301,2302,2305,2307,2309,2311,2313,2315,2317,2320,2322,2324,2326,2328,2330,2332,2334,2336,2338,2341,2343,2345,2347,2349,2351,2354],{"class":404,"line":499},[402,2303,2304],{"class":443},"profileNav.tabBarItem ",[402,2306,597],{"class":433},[402,2308,2247],{"class":603},[402,2310,447],{"class":433},[402,2312,2252],{"class":603},[402,2314,454],{"class":433},[402,2316,531],{"class":433},[402,2318,2319],{"class":534},"我的",[402,2321,538],{"class":433},[402,2323,940],{"class":443},[402,2325,2266],{"class":603},[402,2327,454],{"class":433},[402,2329,2271],{"class":603},[402,2331,447],{"class":433},[402,2333,2276],{"class":603},[402,2335,454],{"class":433},[402,2337,531],{"class":433},[402,2339,2340],{"class":534},"person",[402,2342,538],{"class":433},[402,2344,514],{"class":433},[402,2346,940],{"class":443},[402,2348,2292],{"class":603},[402,2350,454],{"class":433},[402,2352,2353],{"class":590}," 1",[402,2355,460],{"class":433},[402,2357,2358,2361,2363],{"class":404,"line":519},[402,2359,2360],{"class":443},"tabs.viewControllers ",[402,2362,597],{"class":433},[402,2364,2365],{"class":443}," [homeNav, profileNav]\n",[402,2367,2368,2371,2373,2375,2377],{"class":404,"line":556},[402,2369,2370],{"class":443},"window",[402,2372,1588],{"class":433},[402,2374,1985],{"class":443},[402,2376,597],{"class":433},[402,2378,2379],{"class":443}," tabs\n",[179,2381,2382,2383,368],{},"深层链接先选中对应 Tab，再调用那个 Tab 的 ",[183,2384,193],{},[386,2386,2387],{"id":2387},"返回时带数据",[179,2389,2390,2393,2394,2397],{},[183,2391,2392],{},"pop"," 把页面卸掉，参数留在上一个页面。需要回传时，给上一个页面一个闭包或委托，在 ",[183,2395,2396],{},"Router.push"," 创建下一页时接上。路由枚举里放不了闭包。",[386,2399,2400],{"id":2400},"使用时注意",[2402,2403,2404,2418,2427],"ul",{},[2405,2406,2407,2408,2410,2411,2414,2415,2417],"li",{},"跳转放在按钮和 ",[183,2409,193],{}," 里。",[183,2412,2413],{},"viewDidLoad"," 里 ",[183,2416,185],{}," 时，转场经常还没准备好。",[2405,2419,2420,2421,2423,2424,2426],{},"弹层自己要再压栈时，",[183,2422,189],{}," 的是一个新的 ",[183,2425,373],{},"，它和底下那条栈互不影响。",[2405,2428,2429,2431,2432,2435,2436,2438,2439,2441],{},[183,2430,746],{}," 用 ",[183,2433,2434],{},"weak","。控制器被导航栈持有，再强引用 ",[183,2437,193],{},"，而 ",[183,2440,193],{}," 又持有导航控制器，会成环。",[219,2443,239],{"id":2444},"swiftui",[179,2446,2447,2448,2450,2451,2453],{},"SwiftUI 的栈是一份数据。",[183,2449,261],{}," 里有什么，导航栈上就有什么；用户点返回或侧滑，系统会把 ",[183,2452,261],{}," 改回去。",[179,2455,2456,2457,2410,2459,2461],{},"根页面直接写在 ",[183,2458,209],{},[183,2460,261],{}," 从空数组开始，只追加根页面之上的路由。",[386,2463,266],{"id":2464},"目的地-1",[179,2466,2467,2469,2470,2473,2474,368],{},[183,2468,743],{}," 负责压栈，",[183,2471,2472],{},"SheetRoute"," 负责弹层。两条通道各有各的状态，避免把弹层也追加进 ",[183,2475,261],{},[392,2477,2479],{"className":394,"code":2478,"filename":396,"language":397,"meta":398,"style":398},"import Foundation\n\nenum AppRoute: Hashable {\n    case profile(userId: String)\n    case settings\n}\n\nenum SheetRoute: Identifiable {\n    case login\n    case composer\n\n    var id: Self { self }\n}\n\nextension AppRoute {\n    \u002F\u002F\u002F myapp:\u002F\u002Fprofile\u002F42 、myapp:\u002F\u002Fsettings\n    init?(url: URL) {\n        guard url.scheme == \"myapp\" else { return nil }\n        switch url.host {\n        case \"profile\":\n            guard let userId = url.pathComponents.dropFirst().first, !userId.isEmpty else {\n                return nil\n            }\n            self = .profile(userId: userId)\n        case \"settings\":\n            self = .settings\n        default:\n            return nil\n        }\n    }\n}\n",[183,2480,2481,2487,2491,2504,2520,2526,2530,2534,2548,2555,2562,2566,2581,2585,2589,2597,2601,2615,2639,2647,2659,2685,2691,2695,2715,2727,2735,2741,2747,2751,2755],{"__ignoreMap":398},[402,2482,2483,2485],{"class":404,"line":405},[402,2484,409],{"class":408},[402,2486,413],{"class":412},[402,2488,2489],{"class":404,"line":416},[402,2490,420],{"emptyLinePlaceholder":419},[402,2492,2493,2495,2497,2499,2502],{"class":404,"line":423},[402,2494,427],{"class":426},[402,2496,430],{"class":412},[402,2498,454],{"class":433},[402,2500,2501],{"class":412}," Hashable ",[402,2503,565],{"class":433},[402,2505,2506,2508,2510,2512,2514,2516,2518],{"class":404,"line":437},[402,2507,440],{"class":426},[402,2509,444],{"class":443},[402,2511,447],{"class":433},[402,2513,451],{"class":450},[402,2515,454],{"class":433},[402,2517,457],{"class":412},[402,2519,460],{"class":433},[402,2521,2522,2524],{"class":404,"line":463},[402,2523,440],{"class":426},[402,2525,468],{"class":443},[402,2527,2528],{"class":404,"line":471},[402,2529,474],{"class":433},[402,2531,2532],{"class":404,"line":477},[402,2533,420],{"emptyLinePlaceholder":419},[402,2535,2536,2538,2541,2543,2546],{"class":404,"line":482},[402,2537,427],{"class":426},[402,2539,2540],{"class":412}," SheetRoute",[402,2542,454],{"class":433},[402,2544,2545],{"class":412}," Identifiable ",[402,2547,565],{"class":433},[402,2549,2550,2552],{"class":404,"line":492},[402,2551,440],{"class":426},[402,2553,2554],{"class":443}," login\n",[402,2556,2557,2559],{"class":404,"line":499},[402,2558,440],{"class":426},[402,2560,2561],{"class":443}," composer\n",[402,2563,2564],{"class":404,"line":519},[402,2565,420],{"emptyLinePlaceholder":419},[402,2567,2568,2570,2573,2576,2579],{"class":404,"line":556},[402,2569,1582],{"class":590},[402,2571,2572],{"class":443}," id: Self ",[402,2574,2575],{"class":433},"{",[402,2577,2578],{"class":443}," self ",[402,2580,474],{"class":433},[402,2582,2583],{"class":404,"line":568},[402,2584,474],{"class":433},[402,2586,2587],{"class":404,"line":584},[402,2588,420],{"emptyLinePlaceholder":419},[402,2590,2591,2593,2595],{"class":404,"line":624},[402,2592,485],{"class":426},[402,2594,430],{"class":412},[402,2596,434],{"class":433},[402,2598,2599],{"class":404,"line":633},[402,2600,496],{"class":495},[402,2602,2603,2605,2607,2609,2611,2613],{"class":404,"line":639},[402,2604,502],{"class":426},[402,2606,447],{"class":433},[402,2608,508],{"class":507},[402,2610,511],{"class":443},[402,2612,514],{"class":433},[402,2614,434],{"class":433},[402,2616,2617,2619,2621,2623,2625,2627,2629,2631,2633,2635,2637],{"class":404,"line":663},[402,2618,522],{"class":408},[402,2620,525],{"class":443},[402,2622,528],{"class":433},[402,2624,531],{"class":433},[402,2626,535],{"class":534},[402,2628,538],{"class":433},[402,2630,541],{"class":408},[402,2632,544],{"class":433},[402,2634,547],{"class":408},[402,2636,550],{"class":433},[402,2638,553],{"class":433},[402,2640,2641,2643,2645],{"class":404,"line":677},[402,2642,559],{"class":408},[402,2644,562],{"class":443},[402,2646,565],{"class":433},[402,2648,2649,2651,2653,2655,2657],{"class":404,"line":687},[402,2650,571],{"class":408},[402,2652,531],{"class":433},[402,2654,576],{"class":534},[402,2656,538],{"class":433},[402,2658,581],{"class":433},[402,2660,2661,2663,2665,2667,2669,2671,2673,2675,2677,2679,2681,2683],{"class":404,"line":695},[402,2662,587],{"class":408},[402,2664,591],{"class":590},[402,2666,594],{"class":443},[402,2668,597],{"class":433},[402,2670,600],{"class":443},[402,2672,604],{"class":603},[402,2674,607],{"class":433},[402,2676,610],{"class":443},[402,2678,613],{"class":433},[402,2680,616],{"class":443},[402,2682,619],{"class":408},[402,2684,434],{"class":433},[402,2686,2687,2689],{"class":404,"line":703},[402,2688,627],{"class":408},[402,2690,630],{"class":433},[402,2692,2693],{"class":404,"line":709},[402,2694,636],{"class":433},[402,2696,2697,2699,2701,2703,2705,2707,2709,2711,2713],{"class":404,"line":715},[402,2698,642],{"class":443},[402,2700,597],{"class":433},[402,2702,647],{"class":443},[402,2704,576],{"class":603},[402,2706,447],{"class":433},[402,2708,451],{"class":603},[402,2710,454],{"class":433},[402,2712,658],{"class":443},[402,2714,460],{"class":433},[402,2716,2717,2719,2721,2723,2725],{"class":404,"line":1028},[402,2718,571],{"class":408},[402,2720,531],{"class":433},[402,2722,670],{"class":534},[402,2724,538],{"class":433},[402,2726,581],{"class":433},[402,2728,2729,2731,2733],{"class":404,"line":1033},[402,2730,642],{"class":443},[402,2732,597],{"class":433},[402,2734,684],{"class":443},[402,2736,2737,2739],{"class":404,"line":1053},[402,2738,690],{"class":408},[402,2740,581],{"class":433},[402,2742,2743,2745],{"class":404,"line":1088},[402,2744,698],{"class":408},[402,2746,630],{"class":433},[402,2748,2749],{"class":404,"line":1099},[402,2750,706],{"class":433},[402,2752,2753],{"class":404,"line":1119},[402,2754,712],{"class":433},[402,2756,2757],{"class":404,"line":1124},[402,2758,474],{"class":433},[386,2760,193],{"id":2761},"router-1",[392,2763,2765],{"className":394,"code":2764,"filename":765,"language":397,"meta":398,"style":398},"import Observation\n\n@Observable\nfinal class AppRouter {\n    var path: [AppRoute] = []\n    var sheet: SheetRoute?\n\n    func push(_ route: AppRoute) {\n        path.append(route)\n    }\n\n    func pop() {\n        guard !path.isEmpty else { return }\n        path.removeLast()\n    }\n\n    func popToRoot() {\n        path.removeAll()\n    }\n\n    func present(_ route: SheetRoute) {\n        sheet = route\n    }\n\n    func open(url: URL) {\n        guard let route = AppRoute(url: url) else { return }\n        path.append(route)\n    }\n}\n",[183,2766,2767,2774,2778,2786,2796,2816,2825,2829,2847,2862,2866,2870,2880,2898,2907,2911,2915,2925,2934,2938,2942,2961,2971,2975,2979,2995,3025,3037,3041],{"__ignoreMap":398},[402,2768,2769,2771],{"class":404,"line":405},[402,2770,409],{"class":408},[402,2772,2773],{"class":412}," Observation\n",[402,2775,2776],{"class":404,"line":416},[402,2777,420],{"emptyLinePlaceholder":419},[402,2779,2780,2783],{"class":404,"line":423},[402,2781,2782],{"class":433},"@",[402,2784,2785],{"class":426},"Observable\n",[402,2787,2788,2790,2792,2794],{"class":404,"line":437},[402,2789,783],{"class":426},[402,2791,786],{"class":426},[402,2793,789],{"class":412},[402,2795,434],{"class":433},[402,2797,2798,2800,2803,2805,2807,2810,2813],{"class":404,"line":463},[402,2799,1582],{"class":590},[402,2801,2802],{"class":443}," path: ",[402,2804,865],{"class":433},[402,2806,743],{"class":443},[402,2808,2809],{"class":433},"]",[402,2811,2812],{"class":433}," =",[402,2814,2815],{"class":443}," []\n",[402,2817,2818,2820,2823],{"class":404,"line":471},[402,2819,1582],{"class":590},[402,2821,2822],{"class":443}," sheet: SheetRoute",[402,2824,1655],{"class":433},[402,2826,2827],{"class":404,"line":477},[402,2828,420],{"emptyLinePlaceholder":419},[402,2830,2831,2833,2835,2837,2839,2841,2843,2845],{"class":404,"line":482},[402,2832,845],{"class":426},[402,2834,899],{"class":603},[402,2836,447],{"class":433},[402,2838,904],{"class":603},[402,2840,907],{"class":450},[402,2842,910],{"class":443},[402,2844,514],{"class":433},[402,2846,434],{"class":433},[402,2848,2849,2852,2855,2857,2860],{"class":404,"line":492},[402,2850,2851],{"class":443},"        path.",[402,2853,2854],{"class":603},"append",[402,2856,447],{"class":433},[402,2858,2859],{"class":443},"route",[402,2861,460],{"class":433},[402,2863,2864],{"class":404,"line":499},[402,2865,712],{"class":433},[402,2867,2868],{"class":404,"line":519},[402,2869,420],{"emptyLinePlaceholder":419},[402,2871,2872,2874,2876,2878],{"class":404,"line":556},[402,2873,845],{"class":426},[402,2875,964],{"class":603},[402,2877,607],{"class":433},[402,2879,434],{"class":433},[402,2881,2882,2884,2887,2890,2892,2894,2896],{"class":404,"line":568},[402,2883,522],{"class":408},[402,2885,2886],{"class":433}," !",[402,2888,2889],{"class":443},"path.isEmpty ",[402,2891,619],{"class":408},[402,2893,544],{"class":433},[402,2895,547],{"class":408},[402,2897,553],{"class":433},[402,2899,2900,2902,2905],{"class":404,"line":584},[402,2901,2851],{"class":443},[402,2903,2904],{"class":603},"removeLast",[402,2906,1375],{"class":433},[402,2908,2909],{"class":404,"line":624},[402,2910,712],{"class":433},[402,2912,2913],{"class":404,"line":633},[402,2914,420],{"emptyLinePlaceholder":419},[402,2916,2917,2919,2921,2923],{"class":404,"line":639},[402,2918,845],{"class":426},[402,2920,1000],{"class":603},[402,2922,607],{"class":433},[402,2924,434],{"class":433},[402,2926,2927,2929,2932],{"class":404,"line":663},[402,2928,2851],{"class":443},[402,2930,2931],{"class":603},"removeAll",[402,2933,1375],{"class":433},[402,2935,2936],{"class":404,"line":677},[402,2937,712],{"class":433},[402,2939,2940],{"class":404,"line":687},[402,2941,420],{"emptyLinePlaceholder":419},[402,2943,2944,2946,2948,2950,2952,2954,2957,2959],{"class":404,"line":695},[402,2945,845],{"class":426},[402,2947,1038],{"class":603},[402,2949,447],{"class":433},[402,2951,904],{"class":603},[402,2953,907],{"class":450},[402,2955,2956],{"class":443},": SheetRoute",[402,2958,514],{"class":433},[402,2960,434],{"class":433},[402,2962,2963,2966,2968],{"class":404,"line":703},[402,2964,2965],{"class":443},"        sheet ",[402,2967,597],{"class":433},[402,2969,2970],{"class":443}," route\n",[402,2972,2973],{"class":404,"line":709},[402,2974,712],{"class":433},[402,2976,2977],{"class":404,"line":715},[402,2978,420],{"emptyLinePlaceholder":419},[402,2980,2981,2983,2985,2987,2989,2991,2993],{"class":404,"line":1028},[402,2982,845],{"class":426},[402,2984,1180],{"class":603},[402,2986,447],{"class":433},[402,2988,508],{"class":507},[402,2990,511],{"class":443},[402,2992,514],{"class":433},[402,2994,434],{"class":433},[402,2996,2997,2999,3001,3003,3005,3007,3009,3011,3013,3015,3017,3019,3021,3023],{"class":404,"line":1033},[402,2998,522],{"class":408},[402,3000,591],{"class":590},[402,3002,1210],{"class":443},[402,3004,597],{"class":433},[402,3006,430],{"class":603},[402,3008,447],{"class":433},[402,3010,508],{"class":603},[402,3012,454],{"class":433},[402,3014,1223],{"class":443},[402,3016,514],{"class":433},[402,3018,541],{"class":408},[402,3020,544],{"class":433},[402,3022,547],{"class":408},[402,3024,553],{"class":433},[402,3026,3027,3029,3031,3033,3035],{"class":404,"line":1053},[402,3028,2851],{"class":443},[402,3030,2854],{"class":603},[402,3032,447],{"class":433},[402,3034,2859],{"class":443},[402,3036,460],{"class":433},[402,3038,3039],{"class":404,"line":1088},[402,3040,712],{"class":433},[402,3042,3043],{"class":404,"line":1099},[402,3044,474],{"class":433},[179,3046,3047,3048,3050,3051,3053,3054,3056],{},"冷启动时 ",[183,3049,261],{}," 还是空的，",[183,3052,2854],{}," 之后栈就是「首页 + 目标页」，返回回到首页。App 已经打开时再进链接，是在当前 ",[183,3055,261],{}," 后面追加。",[386,3058,3059],{"id":3059},"接到界面上",[179,3061,3062,3065,3066,3068],{},[183,3063,3064],{},"navigationDestination(for:)"," 注册在这个 ",[183,3067,209],{}," 的根内容上，一种路由类型注册一次。",[392,3070,3073],{"className":394,"code":3071,"filename":3072,"language":397,"meta":398,"style":398},"import SwiftUI\n\nstruct AppRoot: View {\n    @State private var router = AppRouter()\n\n    var body: some View {\n        NavigationStack(path: $router.path) {\n            HomeView()\n                .navigationDestination(for: AppRoute.self) { route in\n                    switch route {\n                    case .profile(let userId):\n                        ProfileView(userId: userId)\n                    case .settings:\n                        SettingsView()\n                    }\n                }\n        }\n        .environment(router)\n        .sheet(item: $router.sheet) { route in\n            NavigationStack {\n                switch route {\n                case .login:\n                    LoginView()\n                case .composer:\n                    ComposerView()\n                }\n            }\n        }\n        .onOpenURL { url in\n            router.open(url: url)\n        }\n    }\n}\n","AppRoot.swift",[183,3074,3075,3082,3086,3101,3122,3126,3140,3158,3165,3194,3203,3220,3235,3243,3250,3255,3260,3264,3278,3302,3309,3318,3328,3335,3344,3351,3355,3359,3363,3375,3391,3395,3399],{"__ignoreMap":398},[402,3076,3077,3079],{"class":404,"line":405},[402,3078,409],{"class":408},[402,3080,3081],{"class":412}," SwiftUI\n",[402,3083,3084],{"class":404,"line":416},[402,3085,420],{"emptyLinePlaceholder":419},[402,3087,3088,3091,3094,3096,3099],{"class":404,"line":423},[402,3089,3090],{"class":426},"struct",[402,3092,3093],{"class":412}," AppRoot",[402,3095,454],{"class":433},[402,3097,3098],{"class":412}," View ",[402,3100,565],{"class":433},[402,3102,3103,3106,3109,3112,3114,3116,3118,3120],{"class":404,"line":437},[402,3104,3105],{"class":433},"    @",[402,3107,3108],{"class":426},"State",[402,3110,3111],{"class":590}," private",[402,3113,1650],{"class":590},[402,3115,1881],{"class":443},[402,3117,597],{"class":433},[402,3119,789],{"class":603},[402,3121,1375],{"class":433},[402,3123,3124],{"class":404,"line":463},[402,3125,420],{"emptyLinePlaceholder":419},[402,3127,3128,3130,3133,3136,3138],{"class":404,"line":471},[402,3129,1582],{"class":590},[402,3131,3132],{"class":443}," body: ",[402,3134,3135],{"class":590},"some",[402,3137,3098],{"class":443},[402,3139,565],{"class":433},[402,3141,3142,3145,3147,3149,3151,3154,3156],{"class":404,"line":477},[402,3143,3144],{"class":603},"        NavigationStack",[402,3146,447],{"class":433},[402,3148,261],{"class":603},[402,3150,454],{"class":433},[402,3152,3153],{"class":443}," $router.path",[402,3155,514],{"class":433},[402,3157,434],{"class":433},[402,3159,3160,3163],{"class":404,"line":482},[402,3161,3162],{"class":603},"            HomeView",[402,3164,1375],{"class":433},[402,3166,3167,3170,3173,3175,3177,3179,3182,3185,3187,3189,3191],{"class":404,"line":492},[402,3168,3169],{"class":443},"                .",[402,3171,3172],{"class":603},"navigationDestination",[402,3174,447],{"class":433},[402,3176,931],{"class":603},[402,3178,454],{"class":433},[402,3180,3181],{"class":443}," AppRoute.",[402,3183,3184],{"class":590},"self",[402,3186,514],{"class":433},[402,3188,544],{"class":433},[402,3190,1210],{"class":443},[402,3192,3193],{"class":408},"in\n",[402,3195,3196,3199,3201],{"class":404,"line":499},[402,3197,3198],{"class":408},"                    switch",[402,3200,1210],{"class":443},[402,3202,565],{"class":433},[402,3204,3205,3208,3210,3212,3214,3216,3218],{"class":404,"line":519},[402,3206,3207],{"class":408},"                    case",[402,3209,647],{"class":443},[402,3211,576],{"class":603},[402,3213,447],{"class":433},[402,3215,1461],{"class":590},[402,3217,658],{"class":443},[402,3219,1466],{"class":433},[402,3221,3222,3225,3227,3229,3231,3233],{"class":404,"line":556},[402,3223,3224],{"class":603},"                        ProfileView",[402,3226,447],{"class":433},[402,3228,451],{"class":603},[402,3230,454],{"class":433},[402,3232,658],{"class":443},[402,3234,460],{"class":433},[402,3236,3237,3239,3241],{"class":404,"line":568},[402,3238,3207],{"class":408},[402,3240,1495],{"class":443},[402,3242,581],{"class":433},[402,3244,3245,3248],{"class":404,"line":584},[402,3246,3247],{"class":603},"                        SettingsView",[402,3249,1375],{"class":433},[402,3251,3252],{"class":404,"line":624},[402,3253,3254],{"class":433},"                    }\n",[402,3256,3257],{"class":404,"line":633},[402,3258,3259],{"class":433},"                }\n",[402,3261,3262],{"class":404,"line":639},[402,3263,706],{"class":433},[402,3265,3266,3269,3272,3274,3276],{"class":404,"line":663},[402,3267,3268],{"class":443},"        .",[402,3270,3271],{"class":603},"environment",[402,3273,447],{"class":433},[402,3275,746],{"class":443},[402,3277,460],{"class":433},[402,3279,3280,3282,3284,3286,3289,3291,3294,3296,3298,3300],{"class":404,"line":677},[402,3281,3268],{"class":443},[402,3283,310],{"class":603},[402,3285,447],{"class":433},[402,3287,3288],{"class":603},"item",[402,3290,454],{"class":433},[402,3292,3293],{"class":443}," $router.sheet",[402,3295,514],{"class":433},[402,3297,544],{"class":433},[402,3299,1210],{"class":443},[402,3301,3193],{"class":408},[402,3303,3304,3307],{"class":404,"line":687},[402,3305,3306],{"class":603},"            NavigationStack",[402,3308,434],{"class":433},[402,3310,3311,3314,3316],{"class":404,"line":695},[402,3312,3313],{"class":408},"                switch",[402,3315,1210],{"class":443},[402,3317,565],{"class":433},[402,3319,3320,3323,3326],{"class":404,"line":703},[402,3321,3322],{"class":408},"                case",[402,3324,3325],{"class":443}," .login",[402,3327,581],{"class":433},[402,3329,3330,3333],{"class":404,"line":709},[402,3331,3332],{"class":603},"                    LoginView",[402,3334,1375],{"class":433},[402,3336,3337,3339,3342],{"class":404,"line":715},[402,3338,3322],{"class":408},[402,3340,3341],{"class":443}," .composer",[402,3343,581],{"class":433},[402,3345,3346,3349],{"class":404,"line":1028},[402,3347,3348],{"class":603},"                    ComposerView",[402,3350,1375],{"class":433},[402,3352,3353],{"class":404,"line":1033},[402,3354,3259],{"class":433},[402,3356,3357],{"class":404,"line":1053},[402,3358,636],{"class":433},[402,3360,3361],{"class":404,"line":1088},[402,3362,706],{"class":433},[402,3364,3365,3367,3369,3371,3373],{"class":404,"line":1099},[402,3366,3268],{"class":443},[402,3368,344],{"class":603},[402,3370,544],{"class":433},[402,3372,1912],{"class":443},[402,3374,3193],{"class":408},[402,3376,3377,3379,3381,3383,3385,3387,3389],{"class":404,"line":1119},[402,3378,1929],{"class":443},[402,3380,1932],{"class":603},[402,3382,447],{"class":433},[402,3384,508],{"class":603},[402,3386,454],{"class":433},[402,3388,1223],{"class":443},[402,3390,460],{"class":433},[402,3392,3393],{"class":404,"line":1124},[402,3394,706],{"class":433},[402,3396,3397],{"class":404,"line":1129},[402,3398,712],{"class":433},[402,3400,3401],{"class":404,"line":1141},[402,3402,474],{"class":433},[179,3404,3405,3408,3409,3411,3412,3415,3416,3418,3419,368],{},[183,3406,3407],{},"@State"," 配 ",[183,3410,213],{}," 之后，",[183,3413,3414],{},"$router.path"," 能交给 ",[183,3417,209],{},"。侧滑返回时，系统改的是这份 ",[183,3420,261],{},[179,3422,3423,3424,3426],{},"页面里用环境拿到同一个 ",[183,3425,193],{},"：",[392,3428,3431],{"className":394,"code":3429,"filename":3430,"language":397,"meta":398,"style":398},"import SwiftUI\n\nstruct HomeView: View {\n    @Environment(AppRouter.self) private var router\n\n    var body: some View {\n        List {\n            NavigationLink(value: AppRoute.profile(userId: \"42\")) {\n                Text(\"个人主页\")\n            }\n            Button(\"登录\") {\n                router.present(.login)\n            }\n        }\n        .navigationTitle(\"首页\")\n    }\n}\n","HomeView.swift",[183,3432,3433,3439,3443,3456,3478,3482,3494,3501,3535,3551,3555,3573,3587,3591,3595,3612,3616],{"__ignoreMap":398},[402,3434,3435,3437],{"class":404,"line":405},[402,3436,409],{"class":408},[402,3438,3081],{"class":412},[402,3440,3441],{"class":404,"line":416},[402,3442,420],{"emptyLinePlaceholder":419},[402,3444,3445,3447,3450,3452,3454],{"class":404,"line":423},[402,3446,3090],{"class":426},[402,3448,3449],{"class":412}," HomeView",[402,3451,454],{"class":433},[402,3453,3098],{"class":412},[402,3455,565],{"class":433},[402,3457,3458,3460,3463,3465,3468,3470,3472,3474,3476],{"class":404,"line":437},[402,3459,3105],{"class":433},[402,3461,3462],{"class":426},"Environment",[402,3464,447],{"class":433},[402,3466,3467],{"class":443},"AppRouter.",[402,3469,3184],{"class":590},[402,3471,514],{"class":433},[402,3473,3111],{"class":590},[402,3475,1650],{"class":590},[402,3477,2012],{"class":443},[402,3479,3480],{"class":404,"line":463},[402,3481,420],{"emptyLinePlaceholder":419},[402,3483,3484,3486,3488,3490,3492],{"class":404,"line":471},[402,3485,1582],{"class":590},[402,3487,3132],{"class":443},[402,3489,3135],{"class":590},[402,3491,3098],{"class":443},[402,3493,565],{"class":433},[402,3495,3496,3499],{"class":404,"line":477},[402,3497,3498],{"class":603},"        List",[402,3500,434],{"class":433},[402,3502,3503,3506,3508,3511,3513,3515,3517,3519,3521,3523,3525,3528,3530,3533],{"class":404,"line":482},[402,3504,3505],{"class":603},"            NavigationLink",[402,3507,447],{"class":433},[402,3509,3510],{"class":603},"value",[402,3512,454],{"class":433},[402,3514,3181],{"class":443},[402,3516,576],{"class":603},[402,3518,447],{"class":433},[402,3520,451],{"class":603},[402,3522,454],{"class":433},[402,3524,531],{"class":433},[402,3526,3527],{"class":534},"42",[402,3529,538],{"class":433},[402,3531,3532],{"class":433},"))",[402,3534,434],{"class":433},[402,3536,3537,3540,3542,3544,3547,3549],{"class":404,"line":492},[402,3538,3539],{"class":603},"                Text",[402,3541,447],{"class":433},[402,3543,538],{"class":433},[402,3545,3546],{"class":534},"个人主页",[402,3548,538],{"class":433},[402,3550,460],{"class":433},[402,3552,3553],{"class":404,"line":499},[402,3554,636],{"class":433},[402,3556,3557,3560,3562,3564,3567,3569,3571],{"class":404,"line":519},[402,3558,3559],{"class":603},"            Button",[402,3561,447],{"class":433},[402,3563,538],{"class":433},[402,3565,3566],{"class":534},"登录",[402,3568,538],{"class":433},[402,3570,514],{"class":433},[402,3572,434],{"class":433},[402,3574,3575,3578,3580,3582,3585],{"class":404,"line":556},[402,3576,3577],{"class":443},"                router.",[402,3579,189],{"class":603},[402,3581,447],{"class":433},[402,3583,3584],{"class":443},".login",[402,3586,460],{"class":433},[402,3588,3589],{"class":404,"line":568},[402,3590,636],{"class":433},[402,3592,3593],{"class":404,"line":584},[402,3594,706],{"class":433},[402,3596,3597,3599,3602,3604,3606,3608,3610],{"class":404,"line":624},[402,3598,3268],{"class":443},[402,3600,3601],{"class":603},"navigationTitle",[402,3603,447],{"class":433},[402,3605,538],{"class":433},[402,3607,2259],{"class":534},[402,3609,538],{"class":433},[402,3611,460],{"class":433},[402,3613,3614],{"class":404,"line":633},[402,3615,712],{"class":433},[402,3617,3618],{"class":404,"line":639},[402,3619,474],{"class":433},[179,3621,3622,210,3625,3628,3629,3631],{},[183,3623,3624],{},"NavigationLink(value:)",[183,3626,3627],{},"router.push"," 写入同一条 ",[183,3630,261],{},"。声明式链接和命令式跳转可以并存。",[179,3633,3634,3635,3637,3638,3640],{},"弹层里的 ",[183,3636,209],{}," 是新的一条栈。要在弹层里继续压页面，就给这层单独一个 ",[183,3639,261],{},"，别写进底下那条。",[386,3642,320],{"id":3643},"tab-1",[179,3645,326,3646,3648,3649,3652],{},[183,3647,209],{},"、一个 ",[183,3650,3651],{},"AppRouter","。切走再切回来，各自的栈还在。",[392,3654,3657],{"className":394,"code":3655,"filename":3656,"language":397,"meta":398,"style":398},"import SwiftUI\n\nstruct AppTabs: View {\n    @State private var homeRouter = AppRouter()\n    @State private var profileRouter = AppRouter()\n\n    var body: some View {\n        TabView {\n            NavigationStack(path: $homeRouter.path) {\n                HomeView()\n                    .navigationDestination(for: AppRoute.self) { destination($0) }\n            }\n            .environment(homeRouter)\n            .tabItem { Label(\"首页\", systemImage: \"house\") }\n\n            NavigationStack(path: $profileRouter.path) {\n                ProfileView(userId: \"me\")\n                    .navigationDestination(for: AppRoute.self) { destination($0) }\n            }\n            .environment(profileRouter)\n            .tabItem { Label(\"我的\", systemImage: \"person\") }\n        }\n        .onOpenURL { url in\n            homeRouter.open(url: url)\n        }\n    }\n\n    @ViewBuilder\n    private func destination(_ route: AppRoute) -> some View {\n        switch route {\n        case .profile(let userId):\n            ProfileView(userId: userId)\n        case .settings:\n            SettingsView()\n        }\n    }\n}\n","AppTabs.swift",[183,3658,3659,3665,3669,3682,3700,3718,3722,3734,3741,3758,3765,3798,3802,3816,3853,3857,3874,3894,3924,3928,3941,3975,3979,3991,4008,4012,4016,4020,4027,4054,4062,4078,4093,4101,4108,4112,4116],{"__ignoreMap":398},[402,3660,3661,3663],{"class":404,"line":405},[402,3662,409],{"class":408},[402,3664,3081],{"class":412},[402,3666,3667],{"class":404,"line":416},[402,3668,420],{"emptyLinePlaceholder":419},[402,3670,3671,3673,3676,3678,3680],{"class":404,"line":423},[402,3672,3090],{"class":426},[402,3674,3675],{"class":412}," AppTabs",[402,3677,454],{"class":433},[402,3679,3098],{"class":412},[402,3681,565],{"class":433},[402,3683,3684,3686,3688,3690,3692,3694,3696,3698],{"class":404,"line":437},[402,3685,3105],{"class":433},[402,3687,3108],{"class":426},[402,3689,3111],{"class":590},[402,3691,1650],{"class":590},[402,3693,2168],{"class":443},[402,3695,597],{"class":433},[402,3697,789],{"class":603},[402,3699,1375],{"class":433},[402,3701,3702,3704,3706,3708,3710,3712,3714,3716],{"class":404,"line":463},[402,3703,3105],{"class":433},[402,3705,3108],{"class":426},[402,3707,3111],{"class":590},[402,3709,1650],{"class":590},[402,3711,2190],{"class":443},[402,3713,597],{"class":433},[402,3715,789],{"class":603},[402,3717,1375],{"class":433},[402,3719,3720],{"class":404,"line":471},[402,3721,420],{"emptyLinePlaceholder":419},[402,3723,3724,3726,3728,3730,3732],{"class":404,"line":477},[402,3725,1582],{"class":590},[402,3727,3132],{"class":443},[402,3729,3135],{"class":590},[402,3731,3098],{"class":443},[402,3733,565],{"class":433},[402,3735,3736,3739],{"class":404,"line":482},[402,3737,3738],{"class":603},"        TabView",[402,3740,434],{"class":433},[402,3742,3743,3745,3747,3749,3751,3754,3756],{"class":404,"line":492},[402,3744,3306],{"class":603},[402,3746,447],{"class":433},[402,3748,261],{"class":603},[402,3750,454],{"class":433},[402,3752,3753],{"class":443}," $homeRouter.path",[402,3755,514],{"class":433},[402,3757,434],{"class":433},[402,3759,3760,3763],{"class":404,"line":499},[402,3761,3762],{"class":603},"                HomeView",[402,3764,1375],{"class":433},[402,3766,3767,3770,3772,3774,3776,3778,3780,3782,3784,3786,3789,3791,3794,3796],{"class":404,"line":519},[402,3768,3769],{"class":443},"                    .",[402,3771,3172],{"class":603},[402,3773,447],{"class":433},[402,3775,931],{"class":603},[402,3777,454],{"class":433},[402,3779,3181],{"class":443},[402,3781,3184],{"class":590},[402,3783,514],{"class":433},[402,3785,544],{"class":433},[402,3787,3788],{"class":603}," destination",[402,3790,447],{"class":433},[402,3792,3793],{"class":443},"$0",[402,3795,514],{"class":433},[402,3797,553],{"class":433},[402,3799,3800],{"class":404,"line":556},[402,3801,636],{"class":433},[402,3803,3804,3807,3809,3811,3814],{"class":404,"line":568},[402,3805,3806],{"class":443},"            .",[402,3808,3271],{"class":603},[402,3810,447],{"class":433},[402,3812,3813],{"class":443},"homeRouter",[402,3815,460],{"class":433},[402,3817,3818,3820,3823,3825,3828,3830,3832,3834,3836,3838,3841,3843,3845,3847,3849,3851],{"class":404,"line":584},[402,3819,3806],{"class":443},[402,3821,3822],{"class":603},"tabItem",[402,3824,544],{"class":433},[402,3826,3827],{"class":603}," Label",[402,3829,447],{"class":433},[402,3831,538],{"class":433},[402,3833,2259],{"class":534},[402,3835,538],{"class":433},[402,3837,940],{"class":443},[402,3839,3840],{"class":603},"systemImage",[402,3842,454],{"class":433},[402,3844,531],{"class":433},[402,3846,2283],{"class":534},[402,3848,538],{"class":433},[402,3850,514],{"class":433},[402,3852,553],{"class":433},[402,3854,3855],{"class":404,"line":624},[402,3856,420],{"emptyLinePlaceholder":419},[402,3858,3859,3861,3863,3865,3867,3870,3872],{"class":404,"line":633},[402,3860,3306],{"class":603},[402,3862,447],{"class":433},[402,3864,261],{"class":603},[402,3866,454],{"class":433},[402,3868,3869],{"class":443}," $profileRouter.path",[402,3871,514],{"class":433},[402,3873,434],{"class":433},[402,3875,3876,3879,3881,3883,3885,3887,3890,3892],{"class":404,"line":639},[402,3877,3878],{"class":603},"                ProfileView",[402,3880,447],{"class":433},[402,3882,451],{"class":603},[402,3884,454],{"class":433},[402,3886,531],{"class":433},[402,3888,3889],{"class":534},"me",[402,3891,538],{"class":433},[402,3893,460],{"class":433},[402,3895,3896,3898,3900,3902,3904,3906,3908,3910,3912,3914,3916,3918,3920,3922],{"class":404,"line":663},[402,3897,3769],{"class":443},[402,3899,3172],{"class":603},[402,3901,447],{"class":433},[402,3903,931],{"class":603},[402,3905,454],{"class":433},[402,3907,3181],{"class":443},[402,3909,3184],{"class":590},[402,3911,514],{"class":433},[402,3913,544],{"class":433},[402,3915,3788],{"class":603},[402,3917,447],{"class":433},[402,3919,3793],{"class":443},[402,3921,514],{"class":433},[402,3923,553],{"class":433},[402,3925,3926],{"class":404,"line":677},[402,3927,636],{"class":433},[402,3929,3930,3932,3934,3936,3939],{"class":404,"line":687},[402,3931,3806],{"class":443},[402,3933,3271],{"class":603},[402,3935,447],{"class":433},[402,3937,3938],{"class":443},"profileRouter",[402,3940,460],{"class":433},[402,3942,3943,3945,3947,3949,3951,3953,3955,3957,3959,3961,3963,3965,3967,3969,3971,3973],{"class":404,"line":695},[402,3944,3806],{"class":443},[402,3946,3822],{"class":603},[402,3948,544],{"class":433},[402,3950,3827],{"class":603},[402,3952,447],{"class":433},[402,3954,538],{"class":433},[402,3956,2319],{"class":534},[402,3958,538],{"class":433},[402,3960,940],{"class":443},[402,3962,3840],{"class":603},[402,3964,454],{"class":433},[402,3966,531],{"class":433},[402,3968,2340],{"class":534},[402,3970,538],{"class":433},[402,3972,514],{"class":433},[402,3974,553],{"class":433},[402,3976,3977],{"class":404,"line":703},[402,3978,706],{"class":433},[402,3980,3981,3983,3985,3987,3989],{"class":404,"line":709},[402,3982,3268],{"class":443},[402,3984,344],{"class":603},[402,3986,544],{"class":433},[402,3988,1912],{"class":443},[402,3990,3193],{"class":408},[402,3992,3993,3996,3998,4000,4002,4004,4006],{"class":404,"line":715},[402,3994,3995],{"class":443},"            homeRouter.",[402,3997,1932],{"class":603},[402,3999,447],{"class":433},[402,4001,508],{"class":603},[402,4003,454],{"class":433},[402,4005,1223],{"class":443},[402,4007,460],{"class":433},[402,4009,4010],{"class":404,"line":1028},[402,4011,706],{"class":433},[402,4013,4014],{"class":404,"line":1033},[402,4015,712],{"class":433},[402,4017,4018],{"class":404,"line":1053},[402,4019,420],{"emptyLinePlaceholder":419},[402,4021,4022,4024],{"class":404,"line":1088},[402,4023,3105],{"class":433},[402,4025,4026],{"class":426},"ViewBuilder\n",[402,4028,4029,4031,4033,4035,4037,4039,4041,4043,4045,4047,4050,4052],{"class":404,"line":1099},[402,4030,796],{"class":590},[402,4032,1346],{"class":426},[402,4034,3788],{"class":603},[402,4036,447],{"class":433},[402,4038,904],{"class":603},[402,4040,907],{"class":450},[402,4042,910],{"class":443},[402,4044,514],{"class":433},[402,4046,1354],{"class":433},[402,4048,4049],{"class":590}," some",[402,4051,3098],{"class":443},[402,4053,565],{"class":433},[402,4055,4056,4058,4060],{"class":404,"line":1119},[402,4057,559],{"class":408},[402,4059,1210],{"class":443},[402,4061,565],{"class":433},[402,4063,4064,4066,4068,4070,4072,4074,4076],{"class":404,"line":1124},[402,4065,571],{"class":408},[402,4067,647],{"class":443},[402,4069,576],{"class":603},[402,4071,447],{"class":433},[402,4073,1461],{"class":590},[402,4075,658],{"class":443},[402,4077,1466],{"class":433},[402,4079,4080,4083,4085,4087,4089,4091],{"class":404,"line":1129},[402,4081,4082],{"class":603},"            ProfileView",[402,4084,447],{"class":433},[402,4086,451],{"class":603},[402,4088,454],{"class":433},[402,4090,658],{"class":443},[402,4092,460],{"class":433},[402,4094,4095,4097,4099],{"class":404,"line":1141},[402,4096,571],{"class":408},[402,4098,1495],{"class":443},[402,4100,581],{"class":433},[402,4102,4103,4106],{"class":404,"line":1159},[402,4104,4105],{"class":603},"            SettingsView",[402,4107,1375],{"class":433},[402,4109,4110],{"class":404,"line":1164},[402,4111,706],{"class":433},[402,4113,4114],{"class":404,"line":1169},[402,4115,712],{"class":433},[402,4117,4118],{"class":404,"line":1175},[402,4119,474],{"class":433},[179,4121,4122,4123,4125],{},"链接落在哪个 Tab，就调用哪个 ",[183,4124,193],{},"。上面的例子把链接都送进首页这条栈。",[386,4127,2387],{"id":4128},"返回时带数据-1",[179,4130,4131,4133,4134,4136,4137,4139],{},[183,4132,743],{}," 要 ",[183,4135,274],{},"，闭包放不进去。下一页改完数据，写入两边都能看到的模型，再 ",[183,4138,2392],{},"。上一页从那个模型读结果。",[386,4141,2400],{"id":4142},"使用时注意-1",[2402,4144,4145,4151,4159],{},[2405,4146,4147,4148,4150],{},"目的地页面自己再包一层 ",[183,4149,209],{},"，会变成套娃栈，返回行为会乱。栈只包在根上；弹层要导航时，包在弹层内容外面。",[2405,4152,4153,4155,4156,4158],{},[183,4154,3064],{}," 按类型注册。同一种 ",[183,4157,743],{}," 在同一棵栈上注册一次。",[2405,4160,4161,4162,4164],{},"路由值保持 ",[183,4163,274],{}," 且尽量小。大对象放不进导航状态，进程被系统杀掉再恢复时也带不走。",[219,4166,4167],{"id":4167},"对照着记",[179,4169,4170],{},"同一条产品流程，两边的落点是对齐的。",[223,4172,4173,4184],{},[226,4174,4175],{},[229,4176,4177,4180,4182],{},[232,4178,4179],{},"操作",[232,4181,236],{},[232,4183,239],{},[241,4185,4186,4203,4218,4233,4251,4267],{},[229,4187,4188,4191,4196],{},[246,4189,4190],{},"打开个人主页",[246,4192,4193],{},[183,4194,4195],{},"router.push(.profile(userId: id))",[246,4197,4198,4200,4201],{},[183,4199,4195],{}," 或 ",[183,4202,3624],{},[229,4204,4205,4208,4213],{},[246,4206,4207],{},"回到上一页",[246,4209,4210],{},[183,4211,4212],{},"router.pop()",[246,4214,4215,4217],{},[183,4216,4212],{},"，或用户侧滑",[229,4219,4220,4223,4228],{},[246,4221,4222],{},"回到根",[246,4224,4225],{},[183,4226,4227],{},"router.popToRoot()",[246,4229,4230],{},[183,4231,4232],{},"path.removeAll()",[229,4234,4235,4237,4243],{},[246,4236,300],{},[246,4238,4239,4242],{},[183,4240,4241],{},"router.present(.settings)","，外面再套导航控制器",[246,4244,4245,4248,4249],{},[183,4246,4247],{},"router.present(.login)","，走 ",[183,4250,310],{},[229,4252,4253,4256,4261],{},[246,4254,4255],{},"冷启动进指定页",[246,4257,4258],{},[183,4259,4260],{},"setViewControllers([首页, 目标])",[246,4262,4263,4264],{},"根是首页，",[183,4265,4266],{},"path = [目标]",[229,4268,4269,4272,4275],{},[246,4270,4271],{},"回传结果",[246,4273,4274],{},"闭包或委托",[246,4276,4277,4278],{},"共享的模型，再 ",[183,4279,2392],{},[179,4281,4282,4283,4285,4286,4288],{},"UIKit 的栈里放的是控制器对象，所以冷启动要把首页放进数组第 0 位。SwiftUI 的首页写在 ",[183,4284,209],{}," 的内容位置，",[183,4287,261],{}," 里只有它上面的页。",[219,4290,4291],{"id":4291},"混在一个工程里",[179,4293,4294],{},"老页面是 UIKit、新页面是 SwiftUI 时，路由的边界划在容器上。",[2402,4296,4297,4311],{},[2405,4298,4299,4300,4303,4304,4306,4307,210,4309,368],{},"SwiftUI 页面嵌进 UIKit：用 ",[183,4301,4302],{},"UIHostingController"," 包一层，仍由 UIKit 的 ",[183,4305,193],{}," 负责 ",[183,4308,185],{},[183,4310,189],{},[2405,4312,4313,4314,4317,4318,4320],{},"UIKit 页面嵌进 SwiftUI：用 ",[183,4315,4316],{},"UIViewControllerRepresentable","。这一段内部的压栈留在那个控制器自己的导航控制器里，SwiftUI 的 ",[183,4319,261],{}," 只记录「进入了这块 UIKit」。",[179,4322,4323,4324,210,4326,4329],{},"两条栈各改各的。一块内容同时被 ",[183,4325,261],{},[183,4327,4328],{},"viewControllers"," 推动时，返回顺序会对不上。",[4331,4332,4333],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sjYur, html code.shiki .sjYur{--shiki-light:#6182B8;--shiki-light-font-style:italic;--shiki-default:#82AAFF;--shiki-default-font-style:italic;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":398,"searchDepth":416,"depth":416,"links":4335},[4336,4337,4345,4353,4354],{"id":221,"depth":416,"text":221},{"id":355,"depth":416,"text":236,"children":4338},[4339,4340,4341,4342,4343,4344],{"id":266,"depth":423,"text":266},{"id":746,"depth":423,"text":193},{"id":1726,"depth":423,"text":1726},{"id":2127,"depth":423,"text":320},{"id":2387,"depth":423,"text":2387},{"id":2400,"depth":423,"text":2400},{"id":2444,"depth":416,"text":239,"children":4346},[4347,4348,4349,4350,4351,4352],{"id":2464,"depth":423,"text":266},{"id":2761,"depth":423,"text":193},{"id":3059,"depth":423,"text":3059},{"id":3643,"depth":423,"text":320},{"id":4128,"depth":423,"text":2387},{"id":4142,"depth":423,"text":2400},{"id":4167,"depth":416,"text":4167},{"id":4291,"depth":416,"text":4291},"UIKit 用导航控制器上的页面栈管跳转，SwiftUI 用 NavigationStack 的 path 管跳转。两边都收成一个 Router，目的地用枚举。","md",[4358,4360,4364],{"label":4359,"icon":109,"to":14},"UIKit 起步笔记",{"label":373,"icon":4361,"to":4362,"target":4363},"i-lucide-book-open","https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fuikit\u002Fuinavigationcontroller","_blank",{"label":209,"icon":4361,"to":4365,"target":4363},"https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fswiftui\u002Fnavigationstack",{"date":4367,"categories":4368,"tags":4370},"2026-09-28",[4369],"ios",[108,236,239,4371],"路由",{"icon":48},{"title":4374,"description":4375},"iOS 路由管理：UIKit 与 SwiftUI","用枚举收拢目的地，UIKit 交给持有 UINavigationController 的 Router，SwiftUI 交给持有 NavigationStack path 的 Router。分开记 push、弹层、Tab 和深层链接。","mABOLqa2ZdqvWUnEBWoR1Gu6UDAD3BrzMev1N-lAvvc",[4378,4380],{"title":121,"path":122,"stem":123,"description":4379,"icon":124},"在 Xcode 16 里给 UIKit 项目换启动图。Info 里的 UILaunchScreen 和 LaunchScreen.storyboard 都能做纯色背景、居中 Logo 或整张铺满。",{"title":130,"path":131,"stem":132,"description":4381,"icon":91},"SwiftUI 按所有权从 @State 排到 environment。UIKit 改完模型，再在一处写进控件。页面变大之后用 MVVM 或单向数据流。Combine、RxSwift、ReactorKit、TCA 负责把变化送出去。",1790767047814]