Skip to content

Commit e43a8a7

Browse files
author
Alex Usbergo
committed
push/pop Coordinator context.
1 parent d8c439b commit e43a8a7

File tree

11 files changed

+63
-29
lines changed

11 files changed

+63
-29
lines changed

Demo/CoreRenderDemo/ContentView.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ struct ContentView: View {
2121
.font(UIFont.boldSystemFont(ofSize: 14))
2222
.padding(8)
2323
}
24-
.alignItems(.center)
24+
.alignItems(.flexEnd)
2525
.background(UIColor.systemGroupedBackground)
26-
.matchHostingViewWidth(withMargin: 0)
2726
}
2827
}
2928
}
@@ -32,5 +31,7 @@ struct ContentView: View {
3231
struct ContentView_Previews: PreviewProvider {
3332
static var previews: some View {
3433
ContentView()
34+
.previewLayout(.fixed(width: 320, height: 240))
35+
3536
}
3637
}

Sources/CoreRender/CRContext.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ NS_SWIFT_NAME(Context)
4545

4646
/// Remove the object as delegate (if necessary).
4747
- (void)removeDelegate:(id<CRContextDelegate>)delegate;
48+
/// Make a new context-aware coordinator key.
49+
- (NSString *)makeCoordinatorKey:(NSString *)key;
50+
/// Tell the context that we're in the scope of the given coordinator.
51+
/// @note: This ensure that two different coordinators with the same key in two diferent
52+
/// locations in the hierarchy could exist.
53+
- (void)pushCoordinatorContext:(NSString *)key;
54+
/// Pop the current coordinato context.
55+
- (void)popCoordinatorContext;
4856

4957
@end
5058

Sources/CoreRender/CRContext.mm

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ @implementation CRContext {
3030
NSMutableDictionary<NSString *, NSMutableDictionary<NSString *, CRCoordinator *> *>
3131
*_coordinators;
3232
NSPointerArray *_delegates;
33+
NSMutableArray *_coordinatorPath;
3334
}
3435

3536
- (instancetype)init {
3637
if (self = [super init]) {
3738
_coordinators = @{}.mutableCopy;
3839
_delegates = [NSPointerArray weakObjectsPointerArray];
40+
_coordinatorPath = @[].mutableCopy;
3941
}
4042
return self;
4143
}
@@ -82,4 +84,19 @@ - (void)removeDelegate:(id<CRContextDelegate>)delegate {
8284
if (removeIdx != NSNotFound) [_delegates removePointerAtIndex:removeIdx];
8385
}
8486

87+
- (NSString *)makeCoordinatorKey:(NSString *)key {
88+
return
89+
[NSString stringWithFormat:@"%@/%@", [_coordinatorPath componentsJoinedByString:@"/"], key];
90+
}
91+
92+
- (void)pushCoordinatorContext:(NSString *)key {
93+
CR_ASSERT_ON_MAIN_THREAD();
94+
[_coordinatorPath addObject:key];
95+
}
96+
97+
- (void)popCoordinatorContext {
98+
CR_ASSERT_ON_MAIN_THREAD();
99+
[_coordinatorPath removeLastObject];
100+
}
101+
85102
@end

Sources/CoreRender/CRNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ NS_SWIFT_NAME(ConcreteNode)
4444
/// A custom *reuseIdentifier* is mandatory if the node has a custom creation closure.
4545
@property(nonatomic, readonly) NSString *reuseIdentifier;
4646
/// A unique key for the component/node (necessary if the associated coordinator is stateful).
47-
@property(nonatomic, readonly, nullable) NSString *key;
47+
@property(nonatomic, readonly, nullable) NSString *coordinatorKey;
4848
/// This component is the n-th children.
4949
@property(nonatomic, readonly) NSUInteger index;
5050
/// The subnodes of this node.

Sources/CoreRender/CRNode.mm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ - (instancetype)initWithType:(Class)type
4747
layoutSpec:(void (^)(CRNodeLayoutSpec<UIView *> *))layoutSpec {
4848
if (self = [super init]) {
4949
_reuseIdentifier = CR_NIL_COALESCING(reuseIdentifier, NSStringFromClass(type));
50-
_key = key;
50+
_coordinatorKey = key;
5151
_viewType = type;
5252
_mutableChildren = [[NSMutableArray alloc] init];
5353
self.viewInit = viewInit;
@@ -156,7 +156,7 @@ - (instancetype)bindCoordinator:(CRCoordinatorDescriptor *)descriptor {
156156
#pragma mark - Querying
157157

158158
- (UIView *)viewWithKey:(NSString *)key {
159-
if ([_key isEqualToString:key]) return _renderedView;
159+
if ([_coordinatorKey isEqualToString:key]) return _renderedView;
160160
CR_FOREACH(child, _mutableChildren) {
161161
if (const auto view = [child viewWithKey:key]) return view;
162162
}
@@ -171,7 +171,7 @@ - (UIView *)viewWithKey:(NSString *)key {
171171

172172
- (void)_viewsWithReuseIdentifier:(NSString *)reuseIdentifier
173173
withArray:(NSMutableArray<UIView *> *)array {
174-
if ([_key isEqualToString:reuseIdentifier] && _renderedView) {
174+
if ([_coordinatorKey isEqualToString:reuseIdentifier] && _renderedView) {
175175
[array addObject:_renderedView];
176176
}
177177
CR_FOREACH(child, _mutableChildren) {

Sources/CoreRender/CRNodeBuilder.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ NS_SWIFT_NAME(OpaqueNodeBuilder)
1111
/// @note: This is required if the node has a custom @c viewInit.
1212
- (instancetype)withReuseIdentifier:(NSString *)reuseIdentifier;
1313
/// Unique node key (required for stateful components).
14-
/// @note: This is required if @c coordinatorType or @c state is set.
15-
- (instancetype)withKey:(NSString *)key;
14+
/// @note: Internal only - Use the @c Component class to bind a node to a coordinator.
15+
- (instancetype)_withCoordinatorKey:(NSString *)key;
1616
/// The coordinator assigned to this node.
17-
- (instancetype)withCoordinator:(CRCoordinator *)coordinator;
17+
/// @note: Internal only - Use the @c Component class to bind a node to a coordinator.
18+
- (instancetype)_withCoordinator:(CRCoordinator *)coordinator;
1819
/// The coordinator type assigned to this node.
19-
- (instancetype)withCoordinatorDescriptor:(CRCoordinatorDescriptor *)descriptor;
20+
/// @note: Internal only - Use the @c Component class to bind a node to a coordinator.
21+
- (instancetype)_withCoordinatorDescriptor:(CRCoordinatorDescriptor *)descriptor;
2022
/// Defines the node configuration and layout.
2123
- (instancetype)withLayoutSpec:(void (^)(CRNodeLayoutSpec<UIView *> *))layoutSpec;
2224
/// Build the concrete node.

Sources/CoreRender/CRNodeBuilder.mm

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,23 @@ - (instancetype)withReuseIdentifier:(NSString *)reuseIdentifier {
5353
return self;
5454
}
5555

56-
- (instancetype)withKey:(NSString *)key {
56+
- (instancetype)_withCoordinatorKey:(NSString *)key {
5757
CR_ASSERT_ON_MAIN_THREAD();
5858
_key = key;
5959
return self;
6060
}
6161

62-
- (instancetype)withCoordinatorDescriptor:(CRCoordinatorDescriptor *)descriptor {
62+
- (instancetype)_withCoordinatorDescriptor:(CRCoordinatorDescriptor *)descriptor {
6363
CR_ASSERT_ON_MAIN_THREAD();
6464
_coordinatorDescriptor = descriptor;
6565
return self;
6666
}
6767

68-
- (instancetype)withCoordinator:(CRCoordinator *)coordinator {
68+
- (instancetype)_withCoordinator:(CRCoordinator *)coordinator {
6969
CR_ASSERT_ON_MAIN_THREAD();
7070
const auto descriptor =
7171
[[CRCoordinatorDescriptor alloc] initWithType:coordinator.class key:coordinator.key];
72-
return [self withCoordinatorDescriptor:descriptor];
72+
return [self _withCoordinatorDescriptor:descriptor];
7373
}
7474

7575
- (instancetype)withViewInit:(UIView * (^)(NSString *))viewInit {
@@ -129,19 +129,19 @@ - (instancetype)withReuseIdentifier:(NSString *)reuseIdentifier {
129129
NSAssert(NO, @"Called on abstract super class.");
130130
}
131131

132-
- (instancetype)withKey:(NSString *)key {
132+
- (instancetype)_withCoordinatorKey:(NSString *)key {
133133
NSAssert(NO, @"Called on abstract super class.");
134134
}
135135

136136
- (instancetype)withLayoutSpec:(void (^)(CRNodeLayoutSpec<UIView *> *))layoutSpec {
137137
NSAssert(NO, @"Called on abstract super class.");
138138
}
139139

140-
- (instancetype)withCoordinator:(CRCoordinator *)coordinator {
140+
- (instancetype)_withCoordinator:(CRCoordinator *)coordinator {
141141
NSAssert(NO, @"Called on abstract super class.");
142142
}
143143

144-
- (instancetype)withCoordinatorDescriptor:(CRCoordinatorDescriptor *)descriptor {
144+
- (instancetype)_withCoordinatorDescriptor:(CRCoordinatorDescriptor *)descriptor {
145145
NSAssert(NO, @"Called on abstract super class.");
146146
}
147147

Sources/Render/Bridge.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ public struct Component<C: Coordinator>: OpaqueNodeBuilderConvertible {
1919

2020
public init(
2121
context: Context,
22-
key: String = NSStringFromClass(C.self),
22+
key: String? = nil,
2323
props: [AnyProp] = [],
2424
body: @escaping (Context, C) -> OpaqueNodeBuilder
2525
) {
26+
var argKey: String! = key ?? NSStringFromClass(C.self)
27+
if !argKey.contains("/") {
28+
argKey = context.makeCoordinatorKey(argKey)
29+
}
2630
self.context = context
27-
self.key = key
31+
self.key = argKey
2832
self.props = props
2933
self.body = body
3034
}
@@ -39,7 +43,7 @@ public struct Component<C: Coordinator>: OpaqueNodeBuilderConvertible {
3943
public func makeComponent<C: Coordinator>(
4044
type: C.Type,
4145
context: Context,
42-
key: String = NSStringFromClass(C.self),
46+
key: String,
4347
props: [AnyProp] = [],
4448
body: (Context, C) -> OpaqueNodeBuilder
4549
) -> OpaqueNodeBuilder {
@@ -48,9 +52,12 @@ public func makeComponent<C: Coordinator>(
4852
for setter in props {
4953
setter.apply(coordinator: coordinator)
5054
}
51-
return body(context, coordinator)
55+
context.pushCoordinatorContext(key);
56+
let result = body(context, coordinator)
5257
.withReuseIdentifier(reuseIdentifier)
53-
.withCoordinator(coordinator)
58+
._(with: coordinator)
59+
context.popCoordinatorContext()
60+
return result;
5461
}
5562

5663
// MARK: - OpaqueNodeBuilderConvertible

Sources/Render/CommonNodeTypes.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,13 @@ public func LabelNode(
4545
}
4646

4747
public func ButtonNode(
48-
key: String,
48+
reuseIdentifier: String,
4949
target: Any? = nil,
5050
action: Selector = #selector(Coordinator.onTouchUp(inside:)),
5151
@ContentBuilder builder: () -> ChildrenBuilder = ChildrenBuilder.default
5252
) -> NodeBuilder<UIButton> {
5353
Node(UIButton.self, builder: builder)
54-
.withKey(key)
55-
.withReuseIdentifier(key)
54+
.withReuseIdentifier(reuseIdentifier)
5655
.withViewInit { button in
5756
let button = UIButton()
5857
button.addTarget(target, action: action, for: .touchUpInside)

Tests/RenderTests/BridgeTest.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import XCTest
2-
import CoreRenderObjC
32
import CoreRender
3+
import Render
44

55
class FooCoordinator: Coordinator {
66
var count: Int = 0
@@ -20,7 +20,7 @@ class CRSwiftInteropTests: XCTestCase {
2020
LabelNode(text: "Foor")
2121
LabelNode(text: "Bar")
2222
Component<FooCoordinator>(context: context) { _, _ in
23-
ButtonNode(key: "Hi")
23+
ButtonNode(reuseIdentifier: "Hi")
2424
}
2525
}
2626
}

format_objc.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ format() {
1010
}
1111

1212
echo "Running clang-format..."
13-
cd Sources/CoreRenderObjC && format;
13+
cd Sources/CoreRender && format;
1414
cd ../../;
15-
cd Tests/CoreRenderObjCTests && format;
15+
cd Tests/CoreRenderTests && format;

0 commit comments

Comments
 (0)