@@ -4,40 +4,54 @@ import CocoaAliases
4
4
import Combine
5
5
import FoundationExtensions
6
6
7
+ public protocol GrouppedDestinationProtocol < DestinationID> {
8
+ associatedtype DestinationID : Hashable
9
+
10
+ @_spi ( Internals)
11
+ func _initControllerIfNeeded( for id: DestinationID ) -> CocoaViewController
12
+
13
+ @_spi ( Internals)
14
+ func _invalidateDestination( for id: DestinationID )
15
+ }
16
+
7
17
/// Wrapper for creating and accessing managed navigation stack controllers
8
18
@propertyWrapper
9
19
open class StackDestination <
10
- StackElementID : Hashable ,
20
+ DestinationID : Hashable ,
11
21
Controller: CocoaViewController
12
- > : Weakifiable {
13
- private var _controllers : [ StackElementID : Weak < Controller > ] = [ : ]
22
+ > : Weakifiable , GrouppedDestinationProtocol {
23
+ @_spi ( Internals)
24
+ open var _controllers : [ DestinationID : Controller ] = [ : ]
14
25
15
- open var wrappedValue : [ StackElementID : Controller ] {
16
- let controllers = _controllers. compactMapValues ( \. wrappedValue)
17
- _controllers = controllers. mapValues ( Weak . init ( wrappedValue: ) )
18
- return controllers
26
+ open var wrappedValue : [ DestinationID : Controller ] {
27
+ _controllers
19
28
}
20
29
21
- open var projectedValue : StackDestination < StackElementID , Controller > { self }
30
+ @inlinable
31
+ open var projectedValue : StackDestination < DestinationID , Controller > { self }
22
32
23
- private var _initControllerOverride : ( ( StackElementID ) -> Controller ) ?
33
+ @usableFromInline
34
+ internal var _initControllerOverride : ( ( DestinationID ) -> Controller ) ?
24
35
25
- private var _configuration : ( ( Controller , StackElementID ) -> Void ) ?
36
+ @usableFromInline
37
+ internal var _configuration : ( ( Controller , DestinationID ) -> Void ) ?
26
38
27
39
/// Sets instance-specific override for creating a new controller
28
40
///
29
41
/// This override has the highest priority when creating a new controller
30
42
///
31
43
/// To disable isntance-specific override pass `nil` to this method
44
+ @inlinable
32
45
public func overrideInitController(
33
- with closure: ( ( StackElementID ) -> Controller ) ?
46
+ with closure: ( ( DestinationID ) -> Controller ) ?
34
47
) {
35
48
_initControllerOverride = closure
36
49
}
37
50
38
51
/// Sets instance-specific configuration for controllers
52
+ @inlinable
39
53
public func setConfiguration(
40
- _ closure: ( ( Controller , StackElementID ) -> Void ) ?
54
+ _ closure: ( ( Controller , DestinationID ) -> Void ) ?
41
55
) {
42
56
_configuration = closure
43
57
closure. map { configure in
@@ -47,15 +61,19 @@ open class StackDestination<
47
61
}
48
62
}
49
63
50
- @_spi ( Internals) open class func initController(
51
- for id: StackElementID
64
+ @_spi ( Internals)
65
+ @inlinable
66
+ open class func initController(
67
+ for id: DestinationID
52
68
) -> Controller {
53
69
return Controller ( )
54
70
}
55
71
56
- @_spi ( Internals) open func configureController(
72
+ @_spi ( Internals)
73
+ @inlinable
74
+ open func configureController(
57
75
_ controller: Controller ,
58
- for id: StackElementID
76
+ for id: DestinationID
59
77
) { }
60
78
61
79
/// Creates a new instance
@@ -70,16 +88,31 @@ open class StackDestination<
70
88
/// doesn't have a custom init you'll have to use this method or if you have a base controller that
71
89
/// requires custom init it'll be beneficial for you to create a custom subclass of StackDestination
72
90
/// and override it's `initController` class method, you can find an example in tests.
73
- public convenience init ( _ initControllerOverride: @escaping ( StackElementID ) -> Controller ) {
91
+ @inlinable
92
+ public convenience init ( _ initControllerOverride: @escaping ( DestinationID ) -> Controller ) {
74
93
self . init ( )
75
94
self . overrideInitController ( with: initControllerOverride)
76
95
}
77
96
97
+ @_spi ( Internals)
98
+ @inlinable
99
+ public func _initControllerIfNeeded(
100
+ for id: DestinationID
101
+ ) -> CocoaViewController {
102
+ return self [ id]
103
+ }
104
+
105
+ @_spi ( Internals)
106
+ @inlinable
107
+ open func _invalidateDestination( for id: DestinationID ) {
108
+ self . _controllers. removeValue ( forKey: id)
109
+ }
110
+
78
111
/// Returns `wrappedValue[id]` if present, intializes and configures a new instance otherwise
79
- public subscript( _ id: StackElementID ) -> Controller {
112
+ public subscript( _ id: DestinationID ) -> Controller {
80
113
let controller = wrappedValue [ id] ?? {
81
114
let controller = _initControllerOverride ? ( id) ?? Self . initController ( for: id)
82
- _controllers [ id] = Weak ( controller)
115
+ _controllers [ id] = controller
83
116
configureController ( controller, for: id)
84
117
_configuration ? ( controller, id)
85
118
return controller
@@ -89,3 +122,10 @@ open class StackDestination<
89
122
}
90
123
}
91
124
#endif
125
+
126
+ /*
127
+ - Add erased protocols for Tree/StackDestination with some cleanup function
128
+ - Make RoutingController.destinations method return an instance of the protocol
129
+ - In CocoaViewController+API.swift add custom navigationStack/Destination methods
130
+ - Those methods will inject cleanup function call into onPop handler
131
+ */
0 commit comments