19
19
#import " CBCCatalogExample.h"
20
20
#import " private/CBCRuntime.h"
21
21
22
- void CBCAddNodeFromBreadCrumbs (CBCNode *tree, NSArray <NSString *> *breadCrumbs, Class aClass);
22
+ @interface CBCNode ()
23
+ @property (nonatomic , strong , nullable ) NSMutableDictionary *map;
24
+ @property (nonatomic , strong , nullable ) Class exampleClass;
25
+ @end
23
26
24
27
@implementation CBCNode {
25
- NSMutableDictionary *_map;
26
28
NSMutableArray *_children;
27
- Class _exampleClass;
28
- BOOL _isPresentable;
29
29
}
30
30
31
31
- (instancetype )initWithTitle : (NSString *)title {
32
32
self = [super init ];
33
33
if (self) {
34
34
_title = [title copy ];
35
- _map = [NSMutableDictionary dictionary ];
35
+ self. map = [NSMutableDictionary dictionary ];
36
36
_children = [NSMutableArray array ];
37
- _isPresentable = NO ;
38
37
CBCFixViewDebuggingIfNeeded ();
39
38
}
40
39
return self;
@@ -45,72 +44,75 @@ - (NSComparisonResult)compare:(CBCNode *)otherObject {
45
44
}
46
45
47
46
- (void )addChild : (CBCNode *)child {
48
- _map [child.title] = child;
47
+ self. map [child.title] = child;
49
48
[_children addObject: child];
50
49
}
51
50
52
- - (NSDictionary *)map {
53
- return _map;
54
- }
55
-
56
- - (void )setExampleClass : (Class )exampleClass {
57
- _exampleClass = exampleClass;
58
- }
59
-
60
- - (void )setIsPresentable : (Class )exampleClass {
61
- _isPresentable = CBCCatalogIsPresentableFromClass (exampleClass);
62
- }
63
-
64
51
- (void )finalizeNode {
65
52
_children = [[_children sortedArrayUsingSelector: @selector (compare: )] mutableCopy ];
66
53
}
67
54
68
55
#pragma mark Public
69
56
70
57
- (BOOL )isExample {
71
- return _exampleClass != nil ;
58
+ return self. exampleClass != nil ;
72
59
}
73
60
74
61
- (NSString *)exampleViewControllerName {
62
+ NSAssert (self.exampleClass != nil , @" This node has no associated example." );
75
63
return NSStringFromClass (_exampleClass);
76
64
}
77
65
78
66
- (UIViewController *)createExampleViewController {
79
- NSAssert (_exampleClass != nil , @" This node has no associated example." );
80
- return CBCViewControllerFromClass (_exampleClass );
67
+ NSAssert (self.exampleClass != nil , @" This node has no associated example." );
68
+ return CBCViewControllerFromClass (self. exampleClass , self. metadata );
81
69
}
82
70
83
71
- (NSString *)exampleDescription {
84
- NSAssert (_exampleClass != nil , @" This node has no associated example." );
85
- return CBCDescriptionFromClass (_exampleClass);
72
+ NSString *description = [self .metadata objectForKey: CBCDescription];
73
+ if (description != nil && [description isKindOfClass: [NSString class ]]) {
74
+ return description;
75
+ }
76
+ return nil ;
86
77
}
87
78
88
79
- (NSURL *)exampleRelatedInfo {
89
- NSAssert (_exampleClass != nil , @" This node has no associated example." );
90
- return CBCRelatedInfoFromClass (_exampleClass);
80
+ NSURL *relatedInfo = [self .metadata objectForKey: CBCRelatedInfo];
81
+ if (relatedInfo != nil && [relatedInfo isKindOfClass: [NSURL class ]]) {
82
+ return relatedInfo;
83
+ }
84
+ return nil ;
91
85
}
92
86
93
87
- (BOOL )isPrimaryDemo {
94
- return CBCCatalogIsPrimaryDemoFromClass (_exampleClass);
88
+ id isPrimaryDemo;
89
+ if ((isPrimaryDemo = [self .metadata objectForKey: CBCIsPrimaryDemo]) != nil ) {
90
+ return [isPrimaryDemo boolValue ];
91
+ }
92
+ return NO ;
95
93
}
96
94
97
95
- (BOOL )isPresentable {
98
- return _isPresentable;
96
+ id isPresentable;
97
+ if ((isPresentable = [self .metadata objectForKey: CBCIsPresentable]) != nil ) {
98
+ return [isPresentable boolValue ];
99
+ }
100
+ return NO ;
99
101
}
100
102
101
103
@end
102
104
103
105
@implementation CBCNodeListViewController
104
106
105
107
- (instancetype )initWithNode : (CBCNode *)node {
106
- NSAssert (!_node .isExample, @" %@ cannot represent example nodes." ,
108
+ NSAssert (!self.node .isExample, @" %@ cannot represent example nodes." ,
107
109
NSStringFromClass ([self class ]));
108
110
109
111
self = [super initWithNibName: nil bundle: nil ];
110
112
if (self) {
111
113
_node = node;
112
114
113
- self.title = _node .title ;
115
+ self.title = self. node .title ;
114
116
}
115
117
return self;
116
118
}
@@ -154,7 +156,7 @@ - (void)viewDidAppear:(BOOL)animated {
154
156
#pragma mark - UITableViewDataSource
155
157
156
158
- (NSInteger )tableView : (UITableView *)tableView numberOfRowsInSection : (NSInteger )section {
157
- return (NSInteger )[_node .children count ];
159
+ return (NSInteger )[self .node .children count ];
158
160
}
159
161
160
162
- (UITableViewCell *)tableView : (UITableView *)tableView
@@ -164,15 +166,15 @@ - (UITableViewCell *)tableView:(UITableView *)tableView
164
166
cell =
165
167
[[UITableViewCell alloc ] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: @" cell" ];
166
168
}
167
- cell.textLabel .text = [_node .children[(NSUInteger )indexPath.row] title ];
169
+ cell.textLabel .text = [self .node .children[(NSUInteger )indexPath.row] title ];
168
170
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
169
171
return cell;
170
172
}
171
173
172
174
#pragma mark - UITableViewDelegate
173
175
174
176
- (void )tableView : (UITableView *)tableView didSelectRowAtIndexPath : (NSIndexPath *)indexPath {
175
- CBCNode *node = _node .children [(NSUInteger )indexPath.row];
177
+ CBCNode *node = self. node .children [(NSUInteger )indexPath.row];
176
178
UIViewController *viewController = nil ;
177
179
if ([node isExample ]) {
178
180
viewController = [node createExampleViewController ];
@@ -184,30 +186,61 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
184
186
185
187
@end
186
188
187
- static CBCNode *CBCCreateTreeWithOnlyPresentable (BOOL onlyPresentable) {
188
- NSArray *allClasses = CBCGetAllClasses ();
189
- NSArray *breadcrumbClasses = CBCClassesRespondingToSelector (allClasses,
190
- @selector (catalogBreadcrumbs ));
191
- NSArray *classes;
192
- if (onlyPresentable) {
193
- classes = [breadcrumbClasses filteredArrayUsingPredicate:
194
- [NSPredicate predicateWithBlock: ^BOOL (id object, NSDictionary *bindings) {
195
- return CBCCatalogIsPresentableFromClass (object);
196
- }]];
197
- } else {
198
- classes = breadcrumbClasses;
189
+ static void CBCAddNodeFromBreadCrumbs (CBCNode *tree,
190
+ NSArray <NSString *> *breadCrumbs,
191
+ Class aClass,
192
+ NSDictionary *metadata) {
193
+ // Walk down the navigation tree one breadcrumb at a time, creating nodes along the way.
194
+
195
+ CBCNode *node = tree;
196
+ for (NSUInteger ix = 0 ; ix < [breadCrumbs count ]; ++ix) {
197
+ NSString *title = breadCrumbs[ix];
198
+ BOOL isLastCrumb = ix == [breadCrumbs count ] - 1 ;
199
+
200
+ // Don't walk the last crumb
201
+ if (node.map [title] && !isLastCrumb) {
202
+ node = node.map [title];
203
+ continue ;
204
+ }
205
+
206
+ CBCNode *child = [[CBCNode alloc ] initWithTitle: title];
207
+ [node addChild: child];
208
+ child.metadata = metadata;
209
+ if ([[child.metadata objectForKey: CBCIsPrimaryDemo] boolValue ] == YES ) {
210
+ node.metadata = child.metadata ;
211
+ }
212
+ if ([[child.metadata objectForKey: CBCIsDebug] boolValue ] == YES ) {
213
+ tree.debugLeaf = child;
214
+ }
215
+ node = child;
199
216
}
200
- CBCNode *tree = [[CBCNode alloc ] initWithTitle: @" Root" ];
201
- for (Class aClass in classes) {
202
- // Each example view controller defines its own "breadcrumbs".
203
217
204
- NSArray *breadCrumbs = CBCCatalogBreadcrumbsFromClass (aClass);
218
+ node.exampleClass = aClass;
219
+ }
220
+
221
+ static CBCNode *CBCCreateTreeWithOnlyPresentable (BOOL onlyPresentable) {
222
+ NSArray *allClasses = CBCGetAllCompatibleClasses ();
223
+ NSArray *filteredClasses = [allClasses filteredArrayUsingPredicate:
224
+ [NSPredicate predicateWithBlock: ^BOOL (id object, NSDictionary *bindings) {
225
+ NSDictionary *metadata = CBCCatalogMetadataFromClass (object);
226
+ id breadcrumbs = [metadata objectForKey: CBCBreadcrumbs];
227
+ BOOL validObject = breadcrumbs != nil && [breadcrumbs isKindOfClass: [NSArray class ]];
228
+ if (onlyPresentable) {
229
+ validObject &= ([[metadata objectForKey: CBCIsPresentable] boolValue ] == YES );
230
+ }
231
+ return validObject;
232
+ }]];
205
233
234
+ CBCNode *tree = [[CBCNode alloc ] initWithTitle: @" Root" ];
235
+ for (Class aClass in filteredClasses) {
236
+ // Each example view controller defines its own breadcrumbs (metadata[CBCBreadcrumbs]).
237
+ NSDictionary *metadata = CBCCatalogMetadataFromClass (aClass);
238
+ NSArray *breadCrumbs = [metadata objectForKey: CBCBreadcrumbs];
206
239
if ([[breadCrumbs firstObject ] isKindOfClass: [NSString class ]]) {
207
- CBCAddNodeFromBreadCrumbs (tree, breadCrumbs, aClass);
240
+ CBCAddNodeFromBreadCrumbs (tree, breadCrumbs, aClass, metadata );
208
241
} else if ([[breadCrumbs firstObject ] isKindOfClass: [NSArray class ]]) {
209
242
for (NSArray <NSString *> *parallelBreadCrumb in breadCrumbs) {
210
- CBCAddNodeFromBreadCrumbs (tree, parallelBreadCrumb, aClass);
243
+ CBCAddNodeFromBreadCrumbs (tree, parallelBreadCrumb, aClass, metadata );
211
244
}
212
245
}
213
246
}
@@ -232,30 +265,3 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
232
265
CBCNode *CBCCreatePresentableNavigationTree (void ) {
233
266
return CBCCreateTreeWithOnlyPresentable (YES );
234
267
}
235
-
236
- void CBCAddNodeFromBreadCrumbs (CBCNode *tree, NSArray <NSString *> *breadCrumbs, Class aClass) {
237
- // Walk down the navigation tree one breadcrumb at a time, creating nodes along the way.
238
-
239
- CBCNode *node = tree;
240
- for (NSUInteger ix = 0 ; ix < [breadCrumbs count ]; ++ix) {
241
- NSString *title = breadCrumbs[ix];
242
- BOOL isLastCrumb = ix == [breadCrumbs count ] - 1 ;
243
-
244
- // Don't walk the last crumb
245
-
246
- if (node.map [title] && !isLastCrumb) {
247
- node = node.map [title];
248
- continue ;
249
- }
250
-
251
- CBCNode *child = [[CBCNode alloc ] initWithTitle: title];
252
- [node addChild: child];
253
- [node setIsPresentable: aClass];
254
- if (CBCCatalogIsDebugLeaf (aClass)) {
255
- tree.debugLeaf = child;
256
- }
257
- node = child;
258
- }
259
-
260
- node.exampleClass = aClass;
261
- }
0 commit comments