Skip to content

Commit 7ce3971

Browse files
author
GIKI
committed
commit: add service locator
1 parent 931afdc commit 7ce3971

17 files changed

+415
-54
lines changed

Example/ModuleRouteExample.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
INFOPLIST_KEY_UIMainStoryboardFile = Main;
163163
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
164164
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
165+
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
165166
LD_RUNPATH_SEARCH_PATHS = (
166167
"$(inherited)",
167168
"@executable_path/Frameworks",
@@ -190,6 +191,7 @@
190191
INFOPLIST_KEY_UIMainStoryboardFile = Main;
191192
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
192193
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
194+
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
193195
LD_RUNPATH_SEARCH_PATHS = (
194196
"$(inherited)",
195197
"@executable_path/Frameworks",

Example/ModuleRouteExample/AppDelegate.swift

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,26 @@ import ModuleRoute
1111
@main
1212
class AppDelegate: UIResponder, UIApplicationDelegate {
1313

14-
private var navigator: MRNavigator = MRNavigator()
14+
public lazy var myServiceLocator = startServiceLocator {
15+
AppModule()
16+
}
17+
private var navigator: MRNavigator!
1518

1619

1720
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
1821
setupRoute()
22+
1923
return true
2024
}
2125

26+
private func setupServiceLocator() async {
27+
await myServiceLocator.build()
28+
}
29+
2230
private func setupRoute() {
23-
24-
navigator.register(dependencyFactory: {
25-
DetailModule()
26-
}, forType: DetailInterface.self)
27-
navigator.register(dependencyFactory: {
28-
ChatModule()
29-
}, forType: ChatInterface.self)
30-
31+
navigator = MRNavigator(serviceLocator:myServiceLocator)
32+
navigator.register(moduleType: DetailModule.self)
33+
navigator.register(moduleType: ChatModule.self)
3134
}
3235

3336

@@ -48,3 +51,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
4851

4952
}
5053

54+
55+
class AppModule: ServiceLocatorModule {
56+
57+
override func build() {
58+
single(DetailInterface.self) {
59+
DetailModule()
60+
}
61+
single {
62+
ChatModule()
63+
}
64+
single(ChatInterface.self) {
65+
ChatModule()
66+
}
67+
}
68+
}

Example/ModuleRouteExample/Chat/ChatModule.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import UIKit
99
import ModuleRoute
1010

11-
protocol ChatInterface: MRModuleInterface {
11+
protocol ChatInterface: MRModule {
1212

1313
}
1414

@@ -22,8 +22,8 @@ class ChatModule: ChatInterface {
2222
public func handle(route: MRRoute) -> RouteResult {
2323
// 根据具体路由做出响应
2424
switch route {
25-
case is DetailRoute:
26-
let detail = DetailViewController()
25+
case is ChatRoute:
26+
let detail = ChatViewController()
2727
return .navigator(detail)
2828
default:
2929
return .none

Example/ModuleRouteExample/Chat/ChatViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class ChatViewController: UIViewController {
1111

1212
override func viewDidLoad() {
1313
super.viewDidLoad()
14-
14+
view.backgroundColor = .red
1515
// Do any additional setup after loading the view.
1616
}
1717

Example/ModuleRouteExample/Detail/DetailModule.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Foundation
99
import ModuleRoute
1010
import UIKit
1111

12-
protocol DetailInterface: MRModuleInterface {
12+
protocol DetailInterface: MRModule {
1313

1414
}
1515

@@ -18,9 +18,9 @@ class DetailModule: DetailInterface {
1818
static var supportedRoutes: [MRRoute.Type] = [
1919
DetailRoute.self
2020
]
21+
public init() {
2122

22-
23-
public init() {}
23+
}
2424

2525
public func handle(route: MRRoute) -> RouteResult {
2626

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// PluginInject.swift
3+
// ModuleRouteExample
4+
//
5+
// Created by GIKI on 2025/2/17.
6+
//
7+
8+
import Foundation
9+
import ModuleRoute
10+
import UIKit
11+
12+
@propertyWrapper
13+
internal final class PluginInject<T>: Dependency<T> {
14+
15+
public var wrappedValue: T {
16+
resolvedWrappedValue()
17+
}
18+
19+
public init() {
20+
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
21+
fatalError("Could not access AppDelegate or cast it to the correct type.")
22+
}
23+
super.init(appDelegate.myServiceLocator)
24+
}
25+
}

Example/ModuleRouteExample/ViewController.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import ModuleRoute
1010

1111
class ViewController: UIViewController {
1212

13-
@MRInject var navigator: MRNavigator
14-
@MRInject var detail: DetailInterface
13+
@PluginInject var navigator: MRNavigator
14+
// @Inject(DetailInterface) var detail: DetailInterface
15+
@PluginInject var detail: DetailInterface
16+
1517
// MARK: - Properties
1618
private var collectionView: UICollectionView!
1719
private let cellIdentifier = "Cell"

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import PackageDescription
55

66
let package = Package(
77
name: "ModuleRoute",
8+
platforms: [.iOS(.v14)],
89
products: [
910
// Products define the executables and libraries a package produces, making them visible to other packages.
1011
.library(

Sources/ModuleRoute/MRNavigator.swift

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,38 @@
88
import UIKit
99

1010
public class MRNavigator {
11-
private let container: DependencyContainer
11+
12+
public let serviceLocator: ServiceLocator
1213

1314
private var middlewares: [MRMiddleware] = []
1415
private var interceptors: [MRInterceptor] = []
1516
private var deepLinkParser = DeepLinkParser()
1617
private var logger: MRLogger = DefaultLogger()
1718
private var permissionChecker: MRPermissionChecker = DefaultPermissionChecker()
1819

19-
// 在初始化时,将自身注册到容器中,保证 MRNavigator 也能被注入
20-
public init(container: DependencyContainer = DefaultDependencyContainer.shared) {
21-
self.container = container
22-
// 将当前 navigator 注册为依赖项
23-
self.container.register(dependencyFactory: { self }, forType: MRNavigator.self)
20+
public init(serviceLocator: ServiceLocator) {
21+
self.serviceLocator = serviceLocator
22+
serviceLocator.register {
23+
self
24+
}
25+
if #available(iOS 13.0, *) {
26+
Task{
27+
await serviceLocator.build()
28+
}
29+
}
2430
}
2531

26-
// 修改后的字典,使用 ObjectIdentifier 作为键
27-
private var routeToModuleTypeMap: [ObjectIdentifier: (DependencyContainer) -> MRModuleInterface] = [:]
32+
private var routeToModuleTypeMap: [ObjectIdentifier: (ServiceLocator) -> MRModule] = [:]
2833

29-
// MARK: - Registration
30-
public func register<T>(dependencyFactory: @escaping DependencyFactory, forType type: T.Type) where T: MRModuleInterface {
31-
container.register(dependencyFactory: dependencyFactory, forType: type)
32-
33-
// 将模块的所有支持路由逐一映射到通过容器解析模块实例的闭包
34+
public func register<T: MRModule>(moduleType: T.Type) {
3435
T.supportedRoutes.forEach { routeType in
3536
let key = ObjectIdentifier(routeType)
36-
routeToModuleTypeMap[key] = { container in
37-
// 通过容器获取模块实例
38-
guard let module = container.resolve(T.self) else {
39-
fatalError("Failed to resolve module: \(T.self)")
40-
}
41-
return module
37+
routeToModuleTypeMap[key] = { locator in
38+
return try! locator.resolve() as T
4239
}
4340
}
4441
}
4542

46-
// MARK: - Middleware & Interceptor
4743
public func addMiddleware(_ middleware: MRMiddleware) {
4844
middlewares.append(middleware)
4945
}
@@ -52,25 +48,21 @@ public class MRNavigator {
5248
interceptors.append(interceptor)
5349
}
5450

55-
// MARK: - Navigation
5651
public func navigate(to route: MRRoute,
5752
from viewController: UIViewController,
5853
navigationType: NavigationType = .push,
5954
animated: Bool = true,
6055
completion: (() -> Void)? = nil) {
6156

62-
// 权限检查
6357
if let permissionResult = checkPermission(for: route) {
6458
handleResult(permissionResult, from: viewController, navigationType: navigationType, animated: animated, completion: completion)
6559
return
6660
}
6761

68-
// 通过中间件处理路由,链式调用
6962
let result = processMiddlewares(route: route)
7063
handleResult(result, from: viewController, navigationType: navigationType, animated: animated, completion: completion)
7164
}
7265

73-
// MARK: - DeepLink
7466
public func registerDeepLinkHandler(scheme: String, handler: @escaping (URL) -> MRRoute?) {
7567
deepLinkParser.register(scheme: scheme, handler: handler)
7668
}
@@ -87,7 +79,6 @@ public class MRNavigator {
8779
return false
8880
}
8981

90-
// MARK: - Private Methods
9182
private func processMiddlewares(route: MRRoute, index: Int = 0) -> RouteResult {
9283
if index >= middlewares.count {
9384
return handleRouteDirectly(route: route)
@@ -100,23 +91,20 @@ public class MRNavigator {
10091
}
10192
}
10293

103-
// MARK: - Route Handling
10494
private func handleRouteDirectly(route: MRRoute) -> RouteResult {
105-
// 检查是否有拦截器需要处理当前路由
10695
for interceptor in interceptors {
10796
if interceptor.shouldIntercept(route: route) {
10897
return interceptor.handleInterception(route: route)
10998
}
11099
}
111100

112-
// 通过路由的类型获取模块
113101
let routeTypeKey = ObjectIdentifier(type(of: route))
114102
guard let moduleFactory = routeToModuleTypeMap[routeTypeKey] else {
115103
logger.log(level: .warning, message: "No module found for route: \(type(of: route))", metadata: nil)
116104
return .none
117105
}
118106

119-
let module = moduleFactory(container)
107+
let module = moduleFactory(serviceLocator)
120108
let result = module.handle(route: route)
121109
logRoute(route, result: result)
122110
return result
@@ -138,8 +126,8 @@ public class MRNavigator {
138126
handler()
139127
completion?()
140128
case .service(_),
141-
.value(_),
142-
.none:
129+
.value(_),
130+
.none:
143131
completion?()
144132
}
145133
}

Sources/ModuleRoute/ModuleRoute.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,12 @@ public enum RouteResult {
2323
case none
2424
}
2525

26-
public protocol MRModuleInterface {
26+
27+
public protocol MRModule {
2728
static var supportedRoutes: [MRRoute.Type] { get }
2829
func handle(route: MRRoute) -> RouteResult
2930
}
3031

31-
public protocol MRModule: MRModuleInterface {
32-
33-
}
34-
3532
// MARK: - Basic Route Implementation
3633
public struct BasicRoute: MRRoute {
3734
public static var name: String { "" }

0 commit comments

Comments
 (0)